git.delta.rocks / unique-network / refs/commits / 14137a17488f

difftreelog

feat add FIELDS_COUNT const in AbiType trait

Trubnikov Sergey2022-12-19parent: #3e8db54.patch.diff
in: master

6 files changed

modifiedcrates/evm-coder/procedural/src/abi_derive/derive_enum.rsdiffbeforeafterboth
before · crates/evm-coder/procedural/src/abi_derive/derive_enum.rs
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) -> 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}
after · crates/evm-coder/procedural/src/abi_derive/derive_enum.rs
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}
modifiedcrates/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()
 			}
modifiedcrates/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);
modifiedcrates/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
modifiedcrates/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")
modifiedcrates/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(),