From 7cb20157d17471a32bdfa1f530999bc013376d7c Mon Sep 17 00:00:00 2001 From: Trubnikov Sergey Date: Thu, 10 Nov 2022 09:07:11 +0000 Subject: [PATCH] feat: add derive macro AbiCoder for named struct to implement AbiType --- --- /dev/null +++ b/crates/evm-coder/procedural/src/abi_derive.rs @@ -0,0 +1,66 @@ +use quote::quote; + +pub(crate) fn impl_abi_macro(ast: &syn::DeriveInput) -> proc_macro2::TokenStream { + // dbg!(ast); + let name = &ast.ident; + let can_be_plcaed_in_vec = impl_can_be_placed_in_vec(name); + let abi_type = impl_abi_type(ast); + println!("{}", abi_type); + quote! { + #can_be_plcaed_in_vec + #abi_type + } +} + +fn impl_can_be_placed_in_vec(ident: &syn::Ident) -> proc_macro2::TokenStream { + quote! { + impl ::evm_coder::abi::sealed::CanBePlacedInVec for #ident {} + } +} + +fn impl_abi_type(ast: &syn::DeriveInput) -> proc_macro2::TokenStream { + let name = &ast.ident; + let (fields, params_count) = match &ast.data { + syn::Data::Struct(ds) => match ds.fields { + syn::Fields::Named(ref fields) => ( + fields.named.iter().map(|field| &field.ty), + fields.named.len(), + ), + syn::Fields::Unnamed(_) => todo!(), + syn::Fields::Unit => unimplemented!("Unit structs not supported"), + }, + syn::Data::Enum(_) => unimplemented!("Enums not supported"), + syn::Data::Union(_) => unimplemented!("Unions not supported"), + }; + + let mut params_signature = { + let fields = fields.clone(); + quote!( + #(nameof(<#fields as ::evm_coder::abi::AbiType>::SIGNATURE) fixed(","))* + ) + }; + if params_count > 0 { + params_signature.extend(quote!(shift_left(1))) + }; + + let fields_for_dynamic = fields.clone(); + + quote! { + impl ::evm_coder::abi::AbiType for #name { + const SIGNATURE: ::evm_coder::custom_signature::SignatureUnit = ::evm_coder::make_signature!( + new fixed("(") + #params_signature + fixed(")") + ); + fn is_dynamic() -> bool { + false + #( + || <#fields_for_dynamic as ::evm_coder::abi::AbiType>::is_dynamic() + )* + } + fn size() -> usize { + 0 #(+ <#fields as ::evm_coder::abi::AbiType>::size())* + } + } + } +} --- a/crates/evm-coder/procedural/src/lib.rs +++ b/crates/evm-coder/procedural/src/lib.rs @@ -25,6 +25,7 @@ parse_macro_input, spanned::Spanned, }; +mod abi_derive; mod solidity_interface; mod to_log; @@ -242,3 +243,11 @@ } .into() } + +#[proc_macro_derive(AbiCoder)] +pub fn abi_derive(input: proc_macro::TokenStream) -> proc_macro::TokenStream { + let ast = syn::parse(input).unwrap(); + let ts = abi_derive::impl_abi_macro(&ast); + println!("{}", &ts); + ts.into() +} --- /dev/null +++ b/crates/evm-coder/tests/abi_derive_generation.rs @@ -0,0 +1,203 @@ +use evm_coder_procedural::AbiCoder; +use evm_coder::{ + types::*, + abi::{AbiType}, +}; + +#[derive(AbiCoder)] +struct TypeStructUnit {} + +#[derive(AbiCoder)] +struct TypeStruct1SimpleParam { + _a: u8, +} + +#[derive(AbiCoder)] +struct TypeStruct1DynamicParam { + _a: String, +} + +#[derive(AbiCoder)] +struct TypeStruct2SimpleParam { + _a: u8, + _b: u32, +} + +#[derive(AbiCoder)] +struct TypeStruct2DynamicParam { + _a: String, + _b: bytes, +} + +#[derive(AbiCoder)] +struct TypeStruct2MixedParam { + _a: u8, + _b: bytes, +} + +#[derive(AbiCoder)] +struct TypeStruct1DerivedSimpleParam { + _a: TypeStruct1SimpleParam, +} + +#[derive(AbiCoder)] +struct TypeStruct2DerivedSimpleParam { + _a: TypeStruct1SimpleParam, + _b: TypeStruct2SimpleParam, +} + +#[derive(AbiCoder)] +struct TypeStruct1DerivedDynamicParam { + _a: TypeStruct1DynamicParam, +} + +#[derive(AbiCoder)] +struct TypeStruct2DerivedDynamicParam { + _a: TypeStruct1DynamicParam, + _b: TypeStruct2DynamicParam, +} + +#[derive(AbiCoder)] +struct TypeStruct3DerivedMixedParam { + _a: TypeStruct1SimpleParam, + _b: TypeStruct2DynamicParam, + _c: TypeStruct2MixedParam, +} + +#[test] +fn impl_abi_type_signature() { + assert_eq!( + ::SIGNATURE.as_str().unwrap(), + "()" + ); + assert_eq!( + ::SIGNATURE + .as_str() + .unwrap(), + "(uint8)" + ); + assert_eq!( + ::SIGNATURE + .as_str() + .unwrap(), + "(string)" + ); + assert_eq!( + ::SIGNATURE + .as_str() + .unwrap(), + "(uint8,uint32)" + ); + assert_eq!( + ::SIGNATURE + .as_str() + .unwrap(), + "(string,bytes)" + ); + assert_eq!( + ::SIGNATURE + .as_str() + .unwrap(), + "(uint8,bytes)" + ); + assert_eq!( + ::SIGNATURE + .as_str() + .unwrap(), + "((uint8))" + ); + assert_eq!( + ::SIGNATURE + .as_str() + .unwrap(), + "((uint8),(uint8,uint32))" + ); + assert_eq!( + ::SIGNATURE + .as_str() + .unwrap(), + "((string))" + ); + assert_eq!( + ::SIGNATURE + .as_str() + .unwrap(), + "((string),(string,bytes))" + ); + assert_eq!( + ::SIGNATURE + .as_str() + .unwrap(), + "((uint8),(string,bytes),(uint8,bytes))" + ); +} + +#[test] +fn impl_abi_type_is_dynamic() { + assert_eq!(::is_dynamic(), false); + assert_eq!(::is_dynamic(), false); + assert_eq!(::is_dynamic(), true); + assert_eq!(::is_dynamic(), false); + assert_eq!(::is_dynamic(), true); + assert_eq!(::is_dynamic(), true); + assert_eq!( + ::is_dynamic(), + false + ); + assert_eq!( + ::is_dynamic(), + false + ); + assert_eq!( + ::is_dynamic(), + true + ); + assert_eq!( + ::is_dynamic(), + true + ); + assert_eq!( + ::is_dynamic(), + true + ); +} + +#[test] +fn impl_abi_type_size() { + const ABI_ALIGNMENT: usize = 32; + assert_eq!(::size(), 0); + assert_eq!(::size(), ABI_ALIGNMENT); + assert_eq!(::size(), ABI_ALIGNMENT); + assert_eq!( + ::size(), + ABI_ALIGNMENT * 2 + ); + assert_eq!( + ::size(), + ABI_ALIGNMENT * 2 + ); + assert_eq!( + ::size(), + ABI_ALIGNMENT * 2 + ); + assert_eq!( + ::size(), + ABI_ALIGNMENT + ); + assert_eq!( + ::size(), + ABI_ALIGNMENT * 3 + ); + assert_eq!( + ::size(), + ABI_ALIGNMENT + ); + assert_eq!( + ::size(), + ABI_ALIGNMENT * 3 + ); + assert_eq!( + ::size(), + ABI_ALIGNMENT * 5 + ); +} -- gitstuff