difftreelog
feat add FIELDS_COUNT const in AbiType trait
in: master
6 files changed
crates/evm-coder/procedural/src/abi_derive/derive_enum.rsdiffbeforeafterboth1use quote::quote;23pub fn impl_solidity_option<'a>(4 name: &proc_macro2::Ident,5 enum_options: impl Iterator<Item = &'a syn::Ident>,6) -> proc_macro2::TokenStream {7 let enum_options = enum_options.map(|opt| {8 let s = name.to_string() + "." + opt.to_string().as_str();9 let as_string = proc_macro2::Literal::string(s.as_str());10 quote!(#name::#opt => #as_string,)11 });12 quote!(13 #[cfg(feature = "stubgen")]14 impl ::evm_coder::solidity::SolidityEnum for #name {15 fn solidity_option(&self) -> &str {16 match self {17 #(#enum_options)*18 }19 }20 }21 )22}2324pub fn impl_enum_from_u8<'a>(25 name: &proc_macro2::Ident,26 enum_options: impl Iterator<Item = &'a syn::Ident>,27) -> proc_macro2::TokenStream {28 let error_str = format!("Value not convertible into enum \"{name}\"");29 let error_str = proc_macro2::Literal::string(&error_str);30 let enum_options = enum_options.enumerate().map(|(i, opt)| {31 let n = proc_macro2::Literal::u8_suffixed(i as u8);32 quote! {#n => Ok(#name::#opt),}33 });3435 quote!(36 impl TryFrom<u8> for #name {37 type Error = &'static str;3839 fn try_from(value: u8) -> ::core::result::Result<Self, Self::Error> {40 const err: &'static str = #error_str;41 match value {42 #(#enum_options)*43 _ => Err(err)44 }45 }46 }47 )48}4950pub fn impl_enum_abi_type(name: &syn::Ident) -> proc_macro2::TokenStream {51 quote! {52 impl ::evm_coder::abi::AbiType for #name {53 const SIGNATURE: ::evm_coder::custom_signature::SignatureUnit = <u8 as ::evm_coder::abi::AbiType>::SIGNATURE;5455 fn is_dynamic() -> bool {56 <u8 as ::evm_coder::abi::AbiType>::is_dynamic()57 }58 fn size() -> usize {59 <u8 as ::evm_coder::abi::AbiType>::size()60 }61 }62 }63}6465pub fn impl_enum_abi_read(name: &syn::Ident) -> proc_macro2::TokenStream {66 quote!(67 impl ::evm_coder::abi::AbiRead for #name {68 fn abi_read(reader: &mut ::evm_coder::abi::AbiReader) -> ::evm_coder::execution::Result<Self> {69 Ok(70 <u8 as ::evm_coder::abi::AbiRead>::abi_read(reader)?71 .try_into()?72 )73 }74 }75 )76}7778pub fn impl_enum_abi_write(name: &syn::Ident) -> proc_macro2::TokenStream {79 quote!(80 impl ::evm_coder::abi::AbiWrite for #name {81 fn abi_write(&self, writer: &mut ::evm_coder::abi::AbiWriter) {82 ::evm_coder::abi::AbiWrite::abi_write(&(*self as u8), writer);83 }84 }85 )86}8788pub fn impl_enum_solidity_type_name(name: &syn::Ident) -> proc_macro2::TokenStream {89 quote!(90 #[cfg(feature = "stubgen")]91 impl ::evm_coder::solidity::SolidityTypeName for #name {92 fn solidity_name(93 writer: &mut impl ::core::fmt::Write,94 tc: &::evm_coder::solidity::TypeCollector,95 ) -> ::core::fmt::Result {96 write!(writer, "{}", tc.collect_struct::<Self>())97 }9899 fn is_simple() -> bool {100 true101 }102103 fn solidity_default(104 writer: &mut impl ::core::fmt::Write,105 tc: &::evm_coder::solidity::TypeCollector,106 ) -> ::core::fmt::Result {107 write!(writer, "{}", <#name as ::evm_coder::solidity::SolidityEnum>::solidity_option(&<#name>::default()))108 }109 }110 )111}112113pub fn impl_enum_solidity_struct_collect<'a>(114 name: &syn::Ident,115 enum_options: impl Iterator<Item = &'a syn::Ident>,116 option_count: usize,117 enum_options_docs: impl Iterator<Item = syn::Result<Vec<proc_macro2::TokenStream>>>,118 docs: &[proc_macro2::TokenStream],119) -> proc_macro2::TokenStream {120 let string_name = name.to_string();121 let enum_options = enum_options122 .zip(enum_options_docs)123 .enumerate()124 .map(|(i, (opt, doc))| {125 let opt = proc_macro2::Literal::string(opt.to_string().as_str());126 let doc = doc.expect("Doc parsing error");127 let comma = if i != option_count - 1 { "," } else { "" };128 quote! {129 #(#doc)*130 writeln!(str, "\t{}{}", #opt, #comma).expect("Enum format option");131 }132 });133134 quote!(135 #[cfg(feature = "stubgen")]136 impl ::evm_coder::solidity::StructCollect for #name {137 fn name() -> String {138 #string_name.into()139 }140141 fn declaration() -> String {142 use std::fmt::Write;143144 let mut str = String::new();145 #(#docs)*146 writeln!(str, "enum {} {{", <Self as ::evm_coder::solidity::StructCollect>::name()).unwrap();147 #(#enum_options)*148 writeln!(str, "}}").unwrap();149 str150 }151 }152 )153}154155pub fn check_and_count_options(de: &syn::DataEnum) -> syn::Result<usize> {156 let mut count = 0;157 for v in de.variants.iter() {158 if !v.fields.is_empty() {159 return Err(syn::Error::new(160 v.ident.span(),161 "Enumeration parameters should not have fields",162 ));163 } else if v.discriminant.is_some() {164 return Err(syn::Error::new(165 v.ident.span(),166 "Enumeration options should not have an explicit specified value",167 ));168 } else {169 count += 1;170 }171 }172173 Ok(count)174}175176pub fn check_repr_u8(name: &syn::Ident, attrs: &[syn::Attribute]) -> syn::Result<()> {177 let mut has_repr = false;178 for attr in attrs.iter() {179 if attr.path.is_ident("repr") {180 has_repr = true;181 let meta = attr.parse_meta()?;182 check_meta_u8(&meta)?;183 }184 }185186 if !has_repr {187 return Err(syn::Error::new(name.span(), "Enum is not \"repr(u8)\""));188 }189190 Ok(())191}192193fn check_meta_u8(meta: &syn::Meta) -> Result<(), syn::Error> {194 if let syn::Meta::List(p) = meta {195 for nm in p.nested.iter() {196 if let syn::NestedMeta::Meta(syn::Meta::Path(p)) = nm {197 if !p.is_ident("u8") {198 return Err(syn::Error::new(199 p.segments200 .first()201 .expect("repr segments are empty")202 .ident203 .span(),204 "Enum is not \"repr(u8)\"",205 ));206 }207 }208 }209 }210 Ok(())211}1use quote::quote;23pub fn impl_solidity_option<'a>(4 name: &proc_macro2::Ident,5 enum_options: impl Iterator<Item = &'a syn::Ident>,6) -> proc_macro2::TokenStream {7 let enum_options = enum_options.map(|opt| {8 let s = name.to_string() + "." + opt.to_string().as_str();9 let as_string = proc_macro2::Literal::string(s.as_str());10 quote!(#name::#opt => #as_string,)11 });12 quote!(13 #[cfg(feature = "stubgen")]14 impl ::evm_coder::solidity::SolidityEnum for #name {15 fn solidity_option(&self) -> &str {16 match self {17 #(#enum_options)*18 }19 }20 }21 )22}2324pub fn impl_enum_from_u8<'a>(25 name: &proc_macro2::Ident,26 enum_options: impl Iterator<Item = &'a syn::Ident>,27) -> proc_macro2::TokenStream {28 let error_str = format!("Value not convertible into enum \"{name}\"");29 let error_str = proc_macro2::Literal::string(&error_str);30 let enum_options = enum_options.enumerate().map(|(i, opt)| {31 let n = proc_macro2::Literal::u8_suffixed(i as u8);32 quote! {#n => Ok(#name::#opt),}33 });3435 quote!(36 impl TryFrom<u8> for #name {37 type Error = &'static str;3839 fn try_from(value: u8) -> ::core::result::Result<Self, Self::Error> {40 const err: &'static str = #error_str;41 match value {42 #(#enum_options)*43 _ => Err(err)44 }45 }46 }47 )48}4950pub fn impl_enum_abi_type(name: &syn::Ident, option_count: usize) -> proc_macro2::TokenStream {51 quote! {52 impl ::evm_coder::abi::AbiType for #name {53 const SIGNATURE: ::evm_coder::custom_signature::SignatureUnit = <u8 as ::evm_coder::abi::AbiType>::SIGNATURE;54 const FIELDS_COUNT: usize = #option_count;5556 fn is_dynamic() -> bool {57 <u8 as ::evm_coder::abi::AbiType>::is_dynamic()58 }59 fn size() -> usize {60 <u8 as ::evm_coder::abi::AbiType>::size()61 }62 }63 }64}6566pub fn impl_enum_abi_read(name: &syn::Ident) -> proc_macro2::TokenStream {67 quote!(68 impl ::evm_coder::abi::AbiRead for #name {69 fn abi_read(reader: &mut ::evm_coder::abi::AbiReader) -> ::evm_coder::execution::Result<Self> {70 Ok(71 <u8 as ::evm_coder::abi::AbiRead>::abi_read(reader)?72 .try_into()?73 )74 }75 }76 )77}7879pub fn impl_enum_abi_write(name: &syn::Ident) -> proc_macro2::TokenStream {80 quote!(81 impl ::evm_coder::abi::AbiWrite for #name {82 fn abi_write(&self, writer: &mut ::evm_coder::abi::AbiWriter) {83 ::evm_coder::abi::AbiWrite::abi_write(&(*self as u8), writer);84 }85 }86 )87}8889pub fn impl_enum_solidity_type_name(name: &syn::Ident) -> proc_macro2::TokenStream {90 quote!(91 #[cfg(feature = "stubgen")]92 impl ::evm_coder::solidity::SolidityTypeName for #name {93 fn solidity_name(94 writer: &mut impl ::core::fmt::Write,95 tc: &::evm_coder::solidity::TypeCollector,96 ) -> ::core::fmt::Result {97 write!(writer, "{}", tc.collect_struct::<Self>())98 }99100 fn is_simple() -> bool {101 true102 }103104 fn solidity_default(105 writer: &mut impl ::core::fmt::Write,106 tc: &::evm_coder::solidity::TypeCollector,107 ) -> ::core::fmt::Result {108 write!(writer, "{}", <#name as ::evm_coder::solidity::SolidityEnum>::solidity_option(&<#name>::default()))109 }110 }111 )112}113114pub fn impl_enum_solidity_struct_collect<'a>(115 name: &syn::Ident,116 enum_options: impl Iterator<Item = &'a syn::Ident>,117 option_count: usize,118 enum_options_docs: impl Iterator<Item = syn::Result<Vec<proc_macro2::TokenStream>>>,119 docs: &[proc_macro2::TokenStream],120) -> proc_macro2::TokenStream {121 let string_name = name.to_string();122 let enum_options = enum_options123 .zip(enum_options_docs)124 .enumerate()125 .map(|(i, (opt, doc))| {126 let opt = proc_macro2::Literal::string(opt.to_string().as_str());127 let doc = doc.expect("Doc parsing error");128 let comma = if i != option_count - 1 { "," } else { "" };129 quote! {130 #(#doc)*131 writeln!(str, "\t{}{}", #opt, #comma).expect("Enum format option");132 }133 });134135 quote!(136 #[cfg(feature = "stubgen")]137 impl ::evm_coder::solidity::StructCollect for #name {138 fn name() -> String {139 #string_name.into()140 }141142 fn declaration() -> String {143 use std::fmt::Write;144145 let mut str = String::new();146 #(#docs)*147 writeln!(str, "enum {} {{", <Self as ::evm_coder::solidity::StructCollect>::name()).unwrap();148 #(#enum_options)*149 writeln!(str, "}}").unwrap();150 str151 }152 }153 )154}155156pub fn check_and_count_options(de: &syn::DataEnum) -> syn::Result<usize> {157 let mut count = 0;158 for v in de.variants.iter() {159 if !v.fields.is_empty() {160 return Err(syn::Error::new(161 v.ident.span(),162 "Enumeration parameters should not have fields",163 ));164 } else if v.discriminant.is_some() {165 return Err(syn::Error::new(166 v.ident.span(),167 "Enumeration options should not have an explicit specified value",168 ));169 } else {170 count += 1;171 }172 }173174 Ok(count)175}176177pub fn check_repr_u8(name: &syn::Ident, attrs: &[syn::Attribute]) -> syn::Result<()> {178 let mut has_repr = false;179 for attr in attrs.iter() {180 if attr.path.is_ident("repr") {181 has_repr = true;182 let meta = attr.parse_meta()?;183 check_meta_u8(&meta)?;184 }185 }186187 if !has_repr {188 return Err(syn::Error::new(name.span(), "Enum is not \"repr(u8)\""));189 }190191 Ok(())192}193194fn check_meta_u8(meta: &syn::Meta) -> Result<(), syn::Error> {195 if let syn::Meta::List(p) = meta {196 for nm in p.nested.iter() {197 if let syn::NestedMeta::Meta(syn::Meta::Path(p)) = nm {198 if !p.is_ident("u8") {199 return Err(syn::Error::new(200 p.segments201 .first()202 .expect("repr segments are empty")203 .ident204 .span(),205 "Enum is not \"repr(u8)\"",206 ));207 }208 }209 }210 }211 Ok(())212}crates/evm-coder/procedural/src/abi_derive/derive_struct.rsdiffbeforeafterboth--- a/crates/evm-coder/procedural/src/abi_derive/derive_struct.rs
+++ b/crates/evm-coder/procedural/src/abi_derive/derive_struct.rs
@@ -100,10 +100,12 @@
pub fn impl_struct_abi_type(
name: &syn::Ident,
tuple_type: proc_macro2::TokenStream,
+ fields_count: usize,
) -> proc_macro2::TokenStream {
quote! {
impl ::evm_coder::abi::AbiType for #name {
const SIGNATURE: ::evm_coder::custom_signature::SignatureUnit = <#tuple_type as ::evm_coder::abi::AbiType>::SIGNATURE;
+ const FIELDS_COUNT: usize = #fields_count;
fn is_dynamic() -> bool {
<#tuple_type as ::evm_coder::abi::AbiType>::is_dynamic()
}
crates/evm-coder/procedural/src/abi_derive/mod.rsdiffbeforeafterboth--- a/crates/evm-coder/procedural/src/abi_derive/mod.rs
+++ b/crates/evm-coder/procedural/src/abi_derive/mod.rs
@@ -49,7 +49,7 @@
let struct_from_tuple = struct_from_tuple(name, is_named_fields, field_names.clone());
let can_be_plcaed_in_vec = impl_can_be_placed_in_vec(name);
- let abi_type = impl_struct_abi_type(name, tuple_type.clone());
+ let abi_type = impl_struct_abi_type(name, tuple_type.clone(), params_count);
let abi_read = impl_struct_abi_read(name, tuple_type, tuple_names, struct_from_tuple);
let abi_write = impl_struct_abi_write(name, is_named_fields, tuple_ref_type, tuple_data);
let solidity_type = impl_struct_solidity_type(name, field_types.clone(), params_count);
@@ -83,7 +83,7 @@
let from = impl_enum_from_u8(name, enum_options.clone());
let solidity_option = impl_solidity_option(name, enum_options.clone());
let can_be_plcaed_in_vec = impl_can_be_placed_in_vec(name);
- let abi_type = impl_enum_abi_type(name);
+ let abi_type = impl_enum_abi_type(name, option_count);
let abi_read = impl_enum_abi_read(name);
let abi_write = impl_enum_abi_write(name);
let solidity_type_name = impl_enum_solidity_type_name(name);
crates/evm-coder/src/abi/impls.rsdiffbeforeafterboth--- a/crates/evm-coder/src/abi/impls.rs
+++ b/crates/evm-coder/src/abi/impls.rs
@@ -16,6 +16,7 @@
impl AbiType for $ty {
const SIGNATURE: SignatureUnit = make_signature!(new fixed(stringify!($name)));
+ const FIELDS_COUNT: usize = 1;
fn is_dynamic() -> bool {
$dynamic
@@ -96,6 +97,7 @@
impl<T: AbiType> AbiType for &T {
const SIGNATURE: SignatureUnit = T::SIGNATURE;
+ const FIELDS_COUNT: usize = T::FIELDS_COUNT;
fn is_dynamic() -> bool {
T::is_dynamic()
@@ -125,6 +127,7 @@
impl<T: AbiType> AbiType for Vec<T> {
const SIGNATURE: SignatureUnit = make_signature!(new nameof(T::SIGNATURE) fixed("[]"));
+ const FIELDS_COUNT: usize = 1;
fn is_dynamic() -> bool {
true
@@ -139,6 +142,7 @@
impl AbiType for Property {
const SIGNATURE: SignatureUnit = make_signature!(new fixed("(string,bytes)"));
+ const FIELDS_COUNT: usize = 2;
fn is_dynamic() -> bool {
string::is_dynamic() || bytes::is_dynamic()
@@ -230,6 +234,7 @@
shift_left(1)
fixed(")")
);
+ const FIELDS_COUNT: usize = 0 $(+ {let _ = <$ident as AbiType>::FIELDS_COUNT; 1})+;
fn is_dynamic() -> bool {
false
crates/evm-coder/src/abi/traits.rsdiffbeforeafterboth--- a/crates/evm-coder/src/abi/traits.rs
+++ b/crates/evm-coder/src/abi/traits.rs
@@ -10,6 +10,9 @@
/// Signature for Etherium ABI.
const SIGNATURE: SignatureUnit;
+ /// Count of enum variants or struct fields.
+ const FIELDS_COUNT: usize;
+
/// Signature as str.
fn as_str() -> &'static str {
from_utf8(&Self::SIGNATURE.data[..Self::SIGNATURE.len]).expect("bad utf-8")
crates/evm-coder/tests/abi_derive_generation.rsdiffbeforeafterboth--- a/crates/evm-coder/tests/abi_derive_generation.rs
+++ b/crates/evm-coder/tests/abi_derive_generation.rs
@@ -164,6 +164,50 @@
}
#[test]
+ fn impl_abi_type_fields_count() {
+ assert_eq!(
+ <TypeStruct1SimpleParam as evm_coder::abi::AbiType>::FIELDS_COUNT,
+ 1
+ );
+ assert_eq!(
+ <TypeStruct1DynamicParam as evm_coder::abi::AbiType>::FIELDS_COUNT,
+ 1
+ );
+ assert_eq!(
+ <TypeStruct2SimpleParam as evm_coder::abi::AbiType>::FIELDS_COUNT,
+ 2
+ );
+ assert_eq!(
+ <TypeStruct2DynamicParam as evm_coder::abi::AbiType>::FIELDS_COUNT,
+ 2
+ );
+ assert_eq!(
+ <TypeStruct2MixedParam as evm_coder::abi::AbiType>::FIELDS_COUNT,
+ 2
+ );
+ assert_eq!(
+ <TypeStruct1DerivedSimpleParam as evm_coder::abi::AbiType>::FIELDS_COUNT,
+ 1
+ );
+ assert_eq!(
+ <TypeStruct2DerivedSimpleParam as evm_coder::abi::AbiType>::FIELDS_COUNT,
+ 2
+ );
+ assert_eq!(
+ <TypeStruct1DerivedDynamicParam as evm_coder::abi::AbiType>::FIELDS_COUNT,
+ 2
+ );
+ assert_eq!(
+ <TypeStruct2DerivedDynamicParam as evm_coder::abi::AbiType>::FIELDS_COUNT,
+ 2
+ );
+ assert_eq!(
+ <TypeStruct3DerivedMixedParam as evm_coder::abi::AbiType>::FIELDS_COUNT,
+ 3
+ );
+ }
+
+ #[test]
fn impl_abi_type_is_dynamic() {
assert_eq!(
<TypeStruct1SimpleParam as evm_coder::abi::AbiType>::is_dynamic(),