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 check_enum_fields(de)?;74 let docs = extract_docs(&ast.attrs)?;75 let enum_options = de.variants.iter();7677 let from = impl_enum_from_u8(name, enum_options.clone());78 let solidity_option = impl_solidity_option(docs, name, enum_options.clone());79 let can_be_plcaed_in_vec = impl_can_be_placed_in_vec(name);80 let abi_type = impl_enum_abi_type(name);81 let abi_read = impl_enum_abi_read(name);82 let abi_write = impl_enum_abi_write(name);83 let solidity_type_name = impl_enum_solidity_type_name(name);8485 Ok(quote! {86 #from87 #solidity_option88 #can_be_plcaed_in_vec89 #abi_type90 #abi_read91 #abi_write92 #solidity_type_name93 })94}9596fn extract_docs(attrs: &[syn::Attribute]) -> syn::Result<Vec<String>> {97 attrs98 .iter()99 .filter_map(|attr| {100 if let Some(ps) = attr.path.segments.first() {101 if ps.ident == "doc" {102 let meta = match attr.parse_meta() {103 Ok(meta) => meta,104 Err(e) => return Some(Err(e)),105 };106 match meta {107 syn::Meta::NameValue(mnv) => match &mnv.lit {108 syn::Lit::Str(ls) => return Some(Ok(ls.value())),109 _ => unreachable!(),110 },111 _ => unreachable!(),112 }113 }114 }115 None116 })117 .collect()118}