From 00d3414d19d70edd743453dce8fb96d0bfacf3cc Mon Sep 17 00:00:00 2001 From: Trubnikov Sergey Date: Mon, 14 Nov 2022 14:54:21 +0000 Subject: [PATCH] feat: add implementations of AbiRead & AbiWrite with macto AbiCoder --- --- a/crates/evm-coder/procedural/src/abi_derive.rs +++ b/crates/evm-coder/procedural/src/abi_derive.rs @@ -3,12 +3,40 @@ pub(crate) fn impl_abi_macro(ast: &syn::DeriveInput) -> syn::Result { // dbg!(ast); let name = &ast.ident; + let (is_named_fields, field_names, field_types, params_count) = match &ast.data { + syn::Data::Struct(ds) => match ds.fields { + syn::Fields::Named(ref fields) => Ok(( + true, + fields.named.iter().enumerate().map(map_field_to_name), + fields.named.iter().map(map_field_to_type), + fields.named.len(), + )), + syn::Fields::Unnamed(ref fields) => Ok(( + false, + fields.unnamed.iter().enumerate().map(map_field_to_name), + fields.unnamed.iter().map(map_field_to_type), + fields.unnamed.len(), + )), + syn::Fields::Unit => Err(syn::Error::new(name.span(), "Unit structs not supported")), + }, + syn::Data::Enum(_) => Err(syn::Error::new(name.span(), "Enums not supported")), + syn::Data::Union(_) => Err(syn::Error::new(name.span(), "Unions not supported")), + }?; + + if params_count == 0 { + return Err(syn::Error::new(name.span(), "Empty structs not supported")); + }; + let can_be_plcaed_in_vec = impl_can_be_placed_in_vec(name); - let abi_type = impl_abi_type(ast)?; - // println!("{}", abi_type); + let abi_type = impl_abi_type(name, field_types.clone()); + let abi_read = impl_abi_read(name, is_named_fields, field_names.clone(), field_types); + let abi_write = impl_abi_write(name, is_named_fields, params_count, field_names); + println!("{}", abi_write); Ok(quote! { #can_be_plcaed_in_vec #abi_type + #abi_read + #abi_write }) } @@ -18,44 +46,37 @@ } } +fn map_field_to_name(field: (usize, &syn::Field)) -> syn::Ident { + match field.1.ident.as_ref() { + Some(name) => name.clone(), + None => { + let mut name = "field".to_string(); + name.push_str(field.0.to_string().as_str()); + syn::Ident::new(name.as_str(), proc_macro2::Span::call_site()) + } + } +} + fn map_field_to_type<'a>(field: &'a syn::Field) -> &'a syn::Type { &field.ty } -fn impl_abi_type(ast: &syn::DeriveInput) -> syn::Result { - let name = &ast.ident; - let (fields, params_count) = match &ast.data { - syn::Data::Struct(ds) => match ds.fields { - syn::Fields::Named(ref fields) => Ok(( - fields.named.iter().map(map_field_to_type), - fields.named.len(), - )), - syn::Fields::Unnamed(ref fields) => Ok(( - fields.unnamed.iter().map(map_field_to_type), - fields.unnamed.len(), - )), - syn::Fields::Unit => Err(syn::Error::new(name.span(), "Unit structs not supported")), - }, - syn::Data::Enum(_) => Err(syn::Error::new(name.span(), "Enums not supported")), - syn::Data::Union(_) => Err(syn::Error::new(name.span(), "Unions not supported")), - }?; - +fn impl_abi_type<'a>( + name: &syn::Ident, + field_types: impl Iterator + Clone, +) -> proc_macro2::TokenStream { let mut params_signature = { - let fields = fields.clone(); + let types = field_types.clone(); quote!( - #(nameof(<#fields as ::evm_coder::abi::AbiType>::SIGNATURE) fixed(","))* + #(nameof(<#types as ::evm_coder::abi::AbiType>::SIGNATURE) fixed(","))* ) - }; - - if params_count == 0 { - return Err(syn::Error::new(name.span(), "Empty structs not supported")); }; params_signature.extend(quote!(shift_left(1))); - let fields_for_dynamic = fields.clone(); + let fields_for_dynamic = field_types.clone(); - Ok(quote! { + quote! { impl ::evm_coder::abi::AbiType for #name { const SIGNATURE: ::evm_coder::custom_signature::SignatureUnit = ::evm_coder::make_signature!( new fixed("(") @@ -69,8 +90,71 @@ )* } fn size() -> usize { - 0 #(+ <#fields as ::evm_coder::abi::AbiType>::size())* + 0 #(+ <#field_types as ::evm_coder::abi::AbiType>::size())* + } + } + } +} + +fn impl_abi_read<'a>( + name: &syn::Ident, + is_named_fields: bool, + field_names: impl Iterator + Clone, + field_types: impl Iterator + Clone, +) -> proc_macro2::TokenStream { + let field_names1 = field_names.clone(); + + let struct_constructor = if is_named_fields { + quote!(Ok(Self { #(#field_names1),* })) + } else { + quote!(Ok(Self ( #(#field_names1),* ))) + }; + quote!( + impl ::evm_coder::abi::AbiRead for #name { + fn abi_read(reader: &mut ::evm_coder::abi::AbiReader) -> ::evm_coder::execution::Result { + let size = if !::is_dynamic() { + Some(::size()) + } else { + None + }; + let mut subresult = reader.subresult(size)?; + #( + let #field_names = <#field_types as ::evm_coder::abi::AbiRead>::abi_read(&mut subresult)?; + )* + + #struct_constructor + } + } + ) +} + +fn impl_abi_write<'a>( + name: &syn::Ident, + is_named_fields: bool, + params_count: usize, + field_names: impl Iterator + Clone, +) -> proc_macro2::TokenStream { + let abi_write = if is_named_fields { + quote!( + #( + self.#field_names.abi_write(writer); + )* + ) + } else { + let field_names = (0..params_count) + .into_iter() + .map(proc_macro2::Literal::usize_unsuffixed); + quote!( + #( + self.#field_names.abi_write(writer); + )* + ) + }; + quote!( + impl ::evm_coder::abi::AbiWrite for #name { + fn abi_write(&self, writer: &mut ::evm_coder::abi::AbiWriter) { + #abi_write } } - }) + ) } --- a/crates/evm-coder/src/abi/mod.rs +++ b/crates/evm-coder/src/abi/mod.rs @@ -186,7 +186,7 @@ /// Slice recursive buffer, advance one word for buffer offset /// If `size` is [`None`] then [`Self::offset`] and [`Self::subresult_offset`] evals from [`Self::buf`]. - fn subresult(&mut self, size: Option) -> Result> { + pub fn subresult(&mut self, size: Option) -> Result> { let subresult_offset = self.subresult_offset; let offset = if let Some(size) = size { self.offset += size; --- a/crates/evm-coder/tests/abi_derive_generation.rs +++ b/crates/evm-coder/tests/abi_derive_generation.rs @@ -405,3 +405,8 @@ ::size() ); } + +// #[test] +// fn impl_abi_read() { +// TypeStruct1SimpleParam:: +// } -- gitstuff