1mod derive_enum;2mod derive_struct;34use quote::quote;5use derive_struct::*;6use derive_enum::*;78pub(crate) fn impl_abi_macro(ast: &syn::DeriveInput) -> syn::Result<proc_macro2::TokenStream> {9 let name = &ast.ident;10 match &ast.data {11 syn::Data::Struct(ds) => expand_struct(ds, ast),12 syn::Data::Enum(de) => expand_enum(de, ast),13 syn::Data::Union(_) => Err(syn::Error::new(name.span(), "Unions not supported")),14 }15}1617fn expand_struct(18 ds: &syn::DataStruct,19 ast: &syn::DeriveInput,20) -> syn::Result<proc_macro2::TokenStream> {21 let name = &ast.ident;22 let docs = extract_docs(&ast.attrs)?;23 let (is_named_fields, field_names, field_types, params_count) = match ds.fields {24 syn::Fields::Named(ref fields) => Ok((25 true,26 fields.named.iter().enumerate().map(map_field_to_name),27 fields.named.iter().map(map_field_to_type),28 fields.named.len(),29 )),30 syn::Fields::Unnamed(ref fields) => Ok((31 false,32 fields.unnamed.iter().enumerate().map(map_field_to_name),33 fields.unnamed.iter().map(map_field_to_type),34 fields.unnamed.len(),35 )),36 syn::Fields::Unit => Err(syn::Error::new(name.span(), "Unit structs not supported")),37 }?;3839 if params_count == 0 {40 return Err(syn::Error::new(name.span(), "Empty structs not supported"));41 };4243 let tuple_type = tuple_type(field_types.clone());44 let tuple_ref_type = tuple_ref_type(field_types.clone());45 let tuple_data = tuple_data_as_ref(is_named_fields, field_names.clone());46 let tuple_names = tuple_names(is_named_fields, field_names.clone());47 let struct_from_tuple = struct_from_tuple(name, is_named_fields, field_names.clone());4849 let can_be_plcaed_in_vec = impl_can_be_placed_in_vec(name);50 let abi_type = impl_struct_abi_type(name, tuple_type.clone());51 let abi_read = impl_struct_abi_read(name, tuple_type, tuple_names, struct_from_tuple);52 let abi_write = impl_struct_abi_write(name, is_named_fields, tuple_ref_type, tuple_data);53 let solidity_type = impl_struct_solidity_type(name, docs, ds.fields.iter());54 let solidity_type_name =55 impl_struct_solidity_type_name(name, field_types.clone(), params_count);5657 Ok(quote! {58 #can_be_plcaed_in_vec59 #abi_type60 #abi_read61 #abi_write62 #solidity_type63 #solidity_type_name64 })65}6667fn expand_enum(68 de: &syn::DataEnum,69 ast: &syn::DeriveInput,70) -> syn::Result<proc_macro2::TokenStream> {71 let name = &ast.ident;72 check_repr_u8(name, &ast.attrs)?;73 let docs = extract_docs(&ast.attrs)?;74 let enum_options = de.variants.iter();7576 let from = impl_enum_from_u8(name, enum_options.clone());77 let solidity_option = impl_solidity_option(docs, name, enum_options.clone());78 let can_be_plcaed_in_vec = impl_can_be_placed_in_vec(name);79 let abi_type = impl_enum_abi_type(name);80 let abi_read = impl_enum_abi_read(name);81 let abi_write = impl_enum_abi_write(name);82 let solidity_type_name = impl_enum_solidity_type_name(name);8384 Ok(quote! {85 #from86 #solidity_option87 #can_be_plcaed_in_vec88 #abi_type89 #abi_read90 #abi_write91 #solidity_type_name92 })93}9495fn extract_docs(attrs: &[syn::Attribute]) -> syn::Result<Vec<String>> {96 attrs97 .iter()98 .filter_map(|attr| {99 if let Some(ps) = attr.path.segments.first() {100 if ps.ident == "doc" {101 let meta = match attr.parse_meta() {102 Ok(meta) => meta,103 Err(e) => return Some(Err(e)),104 };105 match meta {106 syn::Meta::NameValue(mnv) => match &mnv.lit {107 syn::Lit::Str(ls) => return Some(Ok(ls.value())),108 _ => unreachable!(),109 },110 _ => unreachable!(),111 }112 }113 }114 None115 })116 .collect()117}