git.delta.rocks / unique-network / refs/commits / e3f5fcba47ee

difftreelog

source

crates/evm-coder-macros/src/solidity_interface.rs22.6 KiBsourcehistory
1#![allow(dead_code)]23use quote::quote;4use darling::{FromMeta, ToTokens};5use inflector::cases;6use std::fmt::Write;7use syn::{8	Expr, FnArg, GenericArgument, Generics, Ident, ImplItem, ImplItemMethod, ItemImpl, Lit, Meta,9	MetaNameValue, NestedMeta, PatType, Path, PathArguments, ReturnType, Type, spanned::Spanned,10};1112use crate::{13	fn_selector_str, parse_ident_from_pat, parse_ident_from_path, parse_path, parse_path_segment,14	parse_result_ok, pascal_ident_to_call, pascal_ident_to_snake_call, snake_ident_to_pascal,15	snake_ident_to_screaming,16};1718struct Is {19	name: Ident,20	pascal_call_name: Ident,21	snake_call_name: Ident,22}23impl Is {24	fn try_from(path: &Path) -> syn::Result<Self> {25		let name = parse_ident_from_path(path, false)?.clone();26		Ok(Self {27			pascal_call_name: pascal_ident_to_call(&name),28			snake_call_name: pascal_ident_to_snake_call(&name),29			name,30		})31	}3233	fn expand_call_def(&self, gen_ref: &proc_macro2::TokenStream) -> proc_macro2::TokenStream {34		let name = &self.name;35		let pascal_call_name = &self.pascal_call_name;36		quote! {37			#name(#pascal_call_name #gen_ref)38		}39	}4041	fn expand_interface_id(&self) -> proc_macro2::TokenStream {42		let pascal_call_name = &self.pascal_call_name;43		quote! {44			interface_id ^= #pascal_call_name::interface_id();45		}46	}4748	fn expand_supports_interface(49		&self,50		generics: &proc_macro2::TokenStream,51	) -> proc_macro2::TokenStream {52		let pascal_call_name = &self.pascal_call_name;53		quote! {54			<#pascal_call_name #generics>::supports_interface(interface_id)55		}56	}5758	fn expand_variant_weight(&self) -> proc_macro2::TokenStream {59		let name = &self.name;60		quote! {61			Self::#name(call) => call.weight()62		}63	}6465	fn expand_variant_call(66		&self,67		call_name: &proc_macro2::Ident,68		generics: &proc_macro2::TokenStream,69	) -> proc_macro2::TokenStream {70		let name = &self.name;71		let pascal_call_name = &self.pascal_call_name;72		quote! {73			#call_name::#name(call) => return <Self as ::evm_coder::Callable<#pascal_call_name #generics>>::call(self, Msg {74				call,75				caller: c.caller,76				value: c.value,77			})78		}79	}8081	fn expand_parse(&self, generics: &proc_macro2::TokenStream) -> proc_macro2::TokenStream {82		let name = &self.name;83		let pascal_call_name = &self.pascal_call_name;84		quote! {85			if let Some(parsed_call) = <#pascal_call_name #generics>::parse(method_id, reader)? {86				return Ok(Some(Self::#name(parsed_call)))87			}88		}89	}9091	fn expand_generator(&self, generics: &proc_macro2::TokenStream) -> proc_macro2::TokenStream {92		let pascal_call_name = &self.pascal_call_name;93		quote! {94			<#pascal_call_name #generics>::generate_solidity_interface(tc, is_impl);95		}96	}9798	fn expand_event_generator(&self) -> proc_macro2::TokenStream {99		let name = &self.name;100		quote! {101			#name::generate_solidity_interface(tc, is_impl);102		}103	}104}105106#[derive(Default)]107struct IsList(Vec<Is>);108impl FromMeta for IsList {109	fn from_list(items: &[NestedMeta]) -> darling::Result<Self> {110		let mut out = Vec::new();111		for item in items {112			match item {113				NestedMeta::Meta(Meta::Path(path)) => out.push(Is::try_from(path)?),114				_ => return Err(syn::Error::new(item.span(), "expected path").into()),115			}116		}117		Ok(Self(out))118	}119}120121#[derive(FromMeta)]122pub struct InterfaceInfo {123	name: Ident,124	#[darling(default)]125	is: IsList,126	#[darling(default)]127	inline_is: IsList,128	#[darling(default)]129	events: IsList,130}131132#[derive(FromMeta)]133struct MethodInfo {134	#[darling(default)]135	rename_selector: Option<String>,136}137138enum AbiType {139	// type140	Plain(Ident),141	// (type1,type2)142	Tuple(Vec<AbiType>),143	// type[]144	Vec(Box<AbiType>),145	// type[20]146	Array(Box<AbiType>, usize),147}148impl AbiType {149	fn try_from(value: &Type) -> syn::Result<Self> {150		let value = Self::try_maybe_special_from(value)?;151		if value.is_special() {152			return Err(syn::Error::new(value.span(), "unexpected special type"));153		}154		Ok(value)155	}156	fn try_maybe_special_from(value: &Type) -> syn::Result<Self> {157		match value {158			Type::Array(arr) => {159				let wrapped = AbiType::try_from(&arr.elem)?;160				match &arr.len {161					Expr::Lit(l) => match &l.lit {162						Lit::Int(i) => {163							let num = i.base10_parse::<usize>()?;164							Ok(AbiType::Array(Box::new(wrapped), num as usize))165						}166						_ => Err(syn::Error::new(arr.len.span(), "should be int literal")),167					},168					_ => Err(syn::Error::new(arr.len.span(), "should be literal")),169				}170			}171			Type::Path(_) => {172				let path = parse_path(value)?;173				let segment = parse_path_segment(path)?;174				if segment.ident == "Vec" {175					let args = match &segment.arguments {176						PathArguments::AngleBracketed(e) => e,177						_ => {178							return Err(syn::Error::new(179								segment.arguments.span(),180								"missing Vec generic",181							))182						}183					};184					let args = &args.args;185					if args.len() != 1 {186						return Err(syn::Error::new(187							args.span(),188							"expected only one generic for vec",189						));190					}191					let arg = args.first().unwrap();192193					let ty = match arg {194						GenericArgument::Type(ty) => ty,195						_ => {196							return Err(syn::Error::new(197								arg.span(),198								"expected first generic to be type",199							))200						}201					};202203					let wrapped = AbiType::try_from(ty)?;204					Ok(Self::Vec(Box::new(wrapped)))205				} else {206					if !segment.arguments.is_empty() {207						return Err(syn::Error::new(208							segment.arguments.span(),209							"unexpected generic arguments for non-vec type",210						));211					}212					Ok(Self::Plain(segment.ident.clone()))213				}214			}215			Type::Tuple(t) => {216				let mut out = Vec::with_capacity(t.elems.len());217				for el in t.elems.iter() {218					out.push(AbiType::try_from(el)?)219				}220				Ok(Self::Tuple(out))221			}222			_ => Err(syn::Error::new(223				value.span(),224				"unexpected type, only arrays, plain types and tuples are supported",225			)),226		}227	}228	fn is_value(&self) -> bool {229		matches!(self, Self::Plain(v) if v == "value")230	}231	fn is_caller(&self) -> bool {232		matches!(self, Self::Plain(v) if v == "caller")233	}234	fn is_special(&self) -> bool {235		self.is_caller() || self.is_value()236	}237	fn selector_ty_buf(&self, buf: &mut String) -> std::fmt::Result {238		match self {239			AbiType::Plain(t) => {240				write!(buf, "{}", t)241			}242			AbiType::Tuple(t) => {243				write!(buf, "(")?;244				for (i, t) in t.iter().enumerate() {245					if i != 0 {246						write!(buf, ",")?;247					}248					t.selector_ty_buf(buf)?;249				}250				write!(buf, ")")251			}252			AbiType::Vec(v) => {253				v.selector_ty_buf(buf)?;254				write!(buf, "[]")255			}256			AbiType::Array(v, len) => {257				v.selector_ty_buf(buf)?;258				write!(buf, "[{}]", len)259			}260		}261	}262	fn selector_ty(&self) -> String {263		let mut out = String::new();264		self.selector_ty_buf(&mut out).expect("no fmt error");265		out266	}267}268impl ToTokens for AbiType {269	fn to_tokens(&self, tokens: &mut proc_macro2::TokenStream) {270		match self {271			AbiType::Plain(t) => tokens.extend(quote! {#t}),272			AbiType::Tuple(t) => {273				tokens.extend(quote! {(274					#(#t),*275				)});276			}277			AbiType::Vec(v) => tokens.extend(quote! {Vec<#v>}),278			AbiType::Array(v, l) => tokens.extend(quote! {[#v; #l]}),279		}280	}281}282283struct MethodArg {284	name: Ident,285	camel_name: String,286	ty: AbiType,287}288impl MethodArg {289	fn try_from(value: &PatType) -> syn::Result<Self> {290		let name = parse_ident_from_pat(&value.pat)?.clone();291		Ok(Self {292			camel_name: cases::camelcase::to_camel_case(&name.to_string()),293			name,294			ty: AbiType::try_maybe_special_from(&value.ty)?,295		})296	}297	fn is_value(&self) -> bool {298		self.ty.is_value()299	}300	fn is_caller(&self) -> bool {301		self.ty.is_caller()302	}303	fn is_special(&self) -> bool {304		self.ty.is_special()305	}306	fn selector_ty(&self) -> String {307		assert!(!self.is_special());308		self.ty.selector_ty()309	}310311	fn expand_call_def(&self) -> proc_macro2::TokenStream {312		assert!(!self.is_special());313		let name = &self.name;314		let ty = &self.ty;315316		quote! {317			#name: #ty318		}319	}320321	fn expand_parse(&self) -> proc_macro2::TokenStream {322		assert!(!self.is_special());323		let name = &self.name;324		quote! {325			#name: reader.abi_read()?326		}327	}328329	fn expand_call_arg(&self) -> proc_macro2::TokenStream {330		if self.is_value() {331			quote! {332				c.value.clone()333			}334		} else if self.is_caller() {335			quote! {336				c.caller.clone()337			}338		} else {339			let name = &self.name;340			quote! {341				#name342			}343		}344	}345346	fn expand_solidity_argument(&self) -> proc_macro2::TokenStream {347		let camel_name = &self.camel_name.to_string();348		let ty = &self.ty;349		quote! {350			<NamedArgument<#ty>>::new(#camel_name)351		}352	}353}354355#[derive(PartialEq)]356enum Mutability {357	Mutable,358	View,359	Pure,360}361362pub struct WeightAttr(syn::Expr);363364mod keyword {365	syn::custom_keyword!(weight);366}367368impl syn::parse::Parse for WeightAttr {369	fn parse(input: syn::parse::ParseStream) -> syn::Result<Self> {370		input.parse::<syn::Token![#]>()?;371		let content;372		syn::bracketed!(content in input);373		content.parse::<keyword::weight>()?;374375		let weight_content;376		syn::parenthesized!(weight_content in content);377		Ok(WeightAttr(weight_content.parse::<syn::Expr>()?))378	}379}380381struct Method {382	name: Ident,383	camel_name: String,384	pascal_name: Ident,385	screaming_name: Ident,386	selector_str: String,387	selector: u32,388	args: Vec<MethodArg>,389	has_normal_args: bool,390	mutability: Mutability,391	result: Type,392	weight: Option<Expr>,393	docs: Vec<String>,394}395impl Method {396	fn try_from(value: &ImplItemMethod) -> syn::Result<Self> {397		let mut info = MethodInfo {398			rename_selector: None,399		};400		let mut docs = Vec::new();401		let mut weight = None;402		for attr in &value.attrs {403			let ident = parse_ident_from_path(&attr.path, false)?;404			if ident == "solidity" {405				let args = attr.parse_meta().unwrap();406				info = MethodInfo::from_meta(&args).unwrap();407			} else if ident == "doc" {408				let args = attr.parse_meta().unwrap();409				let value = match args {410					Meta::NameValue(MetaNameValue {411						lit: Lit::Str(str), ..412					}) => str.value(),413					_ => unreachable!(),414				};415				docs.push(value);416			} else if ident == "weight" {417				weight = Some(syn::parse2::<WeightAttr>(attr.to_token_stream())?.0);418			}419		}420		let ident = &value.sig.ident;421		let ident_str = ident.to_string();422		if !cases::snakecase::is_snake_case(&ident_str) {423			return Err(syn::Error::new(ident.span(), "method name should be snake_cased\nif alternative solidity name needs to be set - use #[solidity] attribute"));424		}425426		let mut mutability = Mutability::Pure;427428		if let Some(FnArg::Receiver(receiver)) = value429			.sig430			.inputs431			.iter()432			.find(|arg| matches!(arg, FnArg::Receiver(_)))433		{434			if receiver.reference.is_none() {435				return Err(syn::Error::new(436					receiver.span(),437					"receiver should be by ref",438				));439			}440			if receiver.mutability.is_some() {441				mutability = Mutability::Mutable;442			} else {443				mutability = Mutability::View;444			}445		}446		let mut args = Vec::new();447		for typ in value448			.sig449			.inputs450			.iter()451			.filter(|arg| matches!(arg, FnArg::Typed(_)))452		{453			let typ = match typ {454				FnArg::Typed(typ) => typ,455				_ => unreachable!(),456			};457			args.push(MethodArg::try_from(typ)?);458		}459460		if mutability != Mutability::Mutable && args.iter().any(|arg| arg.is_value()) {461			return Err(syn::Error::new(462				args.iter().find(|arg| arg.is_value()).unwrap().ty.span(),463				"payable function should be mutable",464			));465		}466467		let result = match &value.sig.output {468			ReturnType::Type(_, ty) => ty,469			_ => return Err(syn::Error::new(value.sig.output.span(), "interface method should return Result<value>\nif there is no value to return - specify void (which is alias to unit)")),470		};471		let result = parse_result_ok(result)?;472473		let camel_name = info474			.rename_selector475			.unwrap_or_else(|| cases::camelcase::to_camel_case(&ident.to_string()));476		let mut selector_str = camel_name.clone();477		selector_str.push('(');478		let mut has_normal_args = false;479		for (i, arg) in args.iter().filter(|arg| !arg.is_special()).enumerate() {480			if i != 0 {481				selector_str.push(',');482			}483			write!(selector_str, "{}", arg.selector_ty()).unwrap();484			has_normal_args = true;485		}486		selector_str.push(')');487		let selector = fn_selector_str(&selector_str);488489		Ok(Self {490			name: ident.clone(),491			camel_name,492			pascal_name: snake_ident_to_pascal(ident),493			screaming_name: snake_ident_to_screaming(ident),494			selector_str,495			selector,496			args,497			has_normal_args,498			mutability,499			result: result.clone(),500			weight,501			docs,502		})503	}504	fn expand_call_def(&self) -> proc_macro2::TokenStream {505		let defs = self506			.args507			.iter()508			.filter(|a| !a.is_special())509			.map(|a| a.expand_call_def());510		let pascal_name = &self.pascal_name;511512		if self.has_normal_args {513			quote! {514				#pascal_name {515					#(516						#defs,517					)*518				}519			}520		} else {521			quote! {#pascal_name}522		}523	}524525	fn expand_const(&self) -> proc_macro2::TokenStream {526		let screaming_name = &self.screaming_name;527		let selector = self.selector;528		let selector_str = &self.selector_str;529		quote! {530			#[doc = #selector_str]531			const #screaming_name: u32 = #selector;532		}533	}534535	fn expand_interface_id(&self) -> proc_macro2::TokenStream {536		let screaming_name = &self.screaming_name;537		quote! {538			interface_id ^= Self::#screaming_name;539		}540	}541542	fn expand_parse(&self) -> proc_macro2::TokenStream {543		let pascal_name = &self.pascal_name;544		let screaming_name = &self.screaming_name;545		if self.has_normal_args {546			let parsers = self547				.args548				.iter()549				.filter(|a| !a.is_special())550				.map(|a| a.expand_parse());551			quote! {552				Self::#screaming_name => return Ok(Some(Self::#pascal_name {553					#(554						#parsers,555					)*556				}))557			}558		} else {559			quote! { Self::#screaming_name => return Ok(Some(Self::#pascal_name)) }560		}561	}562563	fn expand_variant_call(&self, call_name: &proc_macro2::Ident) -> proc_macro2::TokenStream {564		let pascal_name = &self.pascal_name;565		let name = &self.name;566567		let matcher = if self.has_normal_args {568			let names = self569				.args570				.iter()571				.filter(|a| !a.is_special())572				.map(|a| &a.name);573574			quote! {{575				#(576					#names,577				)*578			}}579		} else {580			quote! {}581		};582583		let receiver = match self.mutability {584			Mutability::Mutable | Mutability::View => quote! {self.},585			Mutability::Pure => quote! {Self::},586		};587		let args = self.args.iter().map(|a| a.expand_call_arg());588589		quote! {590			#call_name::#pascal_name #matcher => {591				let result = #receiver #name(592					#(593						#args,594					)*595				)?;596				(&result).to_result()597			}598		}599	}600601	fn expand_variant_weight(&self) -> proc_macro2::TokenStream {602		let pascal_name = &self.pascal_name;603		if let Some(weight) = &self.weight {604			let matcher = if self.has_normal_args {605				let names = self606					.args607					.iter()608					.filter(|a| !a.is_special())609					.map(|a| &a.name);610611				quote! {{612					#(613						#names,614					)*615				}}616			} else {617				quote! {}618			};619			quote! {620				Self::#pascal_name #matcher => (#weight).into()621			}622		} else {623			let matcher = if self.has_normal_args {624				quote! {{..}}625			} else {626				quote! {}627			};628			quote! {629				Self::#pascal_name #matcher => ().into()630			}631		}632	}633634	fn expand_solidity_function(&self) -> proc_macro2::TokenStream {635		let camel_name = &self.camel_name;636		let mutability = match self.mutability {637			Mutability::Mutable => quote! {SolidityMutability::Mutable},638			Mutability::View => quote! { SolidityMutability::View },639			Mutability::Pure => quote! {SolidityMutability::Pure},640		};641		let result = &self.result;642643		let args = self644			.args645			.iter()646			.filter(|a| !a.is_special())647			.map(MethodArg::expand_solidity_argument);648		let docs = self.docs.iter();649		let selector = format!("{} {:0>8x}", self.selector_str, self.selector);650651		quote! {652			SolidityFunction {653				docs: &[#(#docs),*],654				selector: #selector,655				name: #camel_name,656				mutability: #mutability,657				args: (658					#(659						#args,660					)*661				),662				result: <UnnamedArgument<#result>>::default(),663			}664		}665	}666}667668fn generics_list(gen: &Generics) -> proc_macro2::TokenStream {669	if gen.params.is_empty() {670		return quote! {};671	}672	let params = gen.params.iter().map(|p| match p {673		syn::GenericParam::Type(id) => {674			let v = &id.ident;675			quote! {#v}676		}677		syn::GenericParam::Lifetime(lt) => {678			let v = &lt.lifetime;679			quote! {#v}680		}681		syn::GenericParam::Const(c) => {682			let i = &c.ident;683			quote! {#i}684		}685	});686	quote! { #(#params),* }687}688fn generics_reference(gen: &Generics) -> proc_macro2::TokenStream {689	if gen.params.is_empty() {690		return quote! {};691	}692	let list = generics_list(gen);693	quote! { <#list> }694}695fn generics_data(gen: &Generics) -> proc_macro2::TokenStream {696	let list = generics_list(gen);697	if gen.params.len() == 1 {698		quote! {#list}699	} else {700		quote! { (#list) }701	}702}703704pub struct SolidityInterface {705	generics: Generics,706	name: Box<syn::Type>,707	info: InterfaceInfo,708	methods: Vec<Method>,709}710impl SolidityInterface {711	pub fn try_from(info: InterfaceInfo, value: &ItemImpl) -> syn::Result<Self> {712		let mut methods = Vec::new();713714		for item in &value.items {715			if let ImplItem::Method(method) = item {716				methods.push(Method::try_from(method)?)717			}718		}719		Ok(Self {720			generics: value.generics.clone(),721			name: value.self_ty.clone(),722			info,723			methods,724		})725	}726	pub fn expand(self) -> proc_macro2::TokenStream {727		let name = self.name;728729		let solidity_name = self.info.name.to_string();730		let call_name = pascal_ident_to_call(&self.info.name);731		let generics = self.generics;732		let gen_ref = generics_reference(&generics);733		let gen_data = generics_data(&generics);734735		let call_sub = self736			.info737			.inline_is738			.0739			.iter()740			.chain(self.info.is.0.iter())741			.map(|c| Is::expand_call_def(c, &gen_ref));742		let call_parse = self743			.info744			.inline_is745			.0746			.iter()747			.chain(self.info.is.0.iter())748			.map(|is| Is::expand_parse(is, &gen_ref));749		let call_variants = self750			.info751			.inline_is752			.0753			.iter()754			.chain(self.info.is.0.iter())755			.map(|c| Is::expand_variant_call(c, &call_name, &gen_ref));756		let weight_variants = self757			.info758			.inline_is759			.0760			.iter()761			.chain(self.info.is.0.iter())762			.map(Is::expand_variant_weight);763764		let inline_interface_id = self.info.inline_is.0.iter().map(Is::expand_interface_id);765		let supports_interface = self766			.info767			.is768			.0769			.iter()770			.map(|is| Is::expand_supports_interface(is, &gen_ref));771772		let calls = self.methods.iter().map(Method::expand_call_def);773		let consts = self.methods.iter().map(Method::expand_const);774		let interface_id = self.methods.iter().map(Method::expand_interface_id);775		let parsers = self.methods.iter().map(Method::expand_parse);776		let call_variants_this = self777			.methods778			.iter()779			.map(|m| Method::expand_variant_call(m, &call_name));780		let weight_variants_this = self.methods.iter().map(Method::expand_variant_weight);781		let solidity_functions = self.methods.iter().map(Method::expand_solidity_function);782783		// TODO: Inline inline_is784		let solidity_is = self785			.info786			.is787			.0788			.iter()789			.chain(self.info.inline_is.0.iter())790			.map(|is| is.name.to_string());791		let solidity_events_is = self.info.events.0.iter().map(|is| is.name.to_string());792		let solidity_generators = self793			.info794			.is795			.0796			.iter()797			.chain(self.info.inline_is.0.iter())798			.map(|is| Is::expand_generator(is, &gen_ref));799		let solidity_event_generators = self.info.events.0.iter().map(Is::expand_event_generator);800801		// let methods = self.methods.iter().map(Method::solidity_def);802803		quote! {804			#[derive(Debug)]805			pub enum #call_name #gen_ref {806				ERC165Call(::evm_coder::ERC165Call, ::core::marker::PhantomData<#gen_data>),807				#(808					#calls,809				)*810				#(811					#call_sub,812				)*813			}814			impl #gen_ref #call_name #gen_ref {815				#(816					#consts817				)*818				pub fn interface_id() -> u32 {819					let mut interface_id = 0;820					#(#interface_id)*821					#(#inline_interface_id)*822					interface_id823				}824				pub fn supports_interface(interface_id: u32) -> bool {825					interface_id != 0xffffff && (826						interface_id == ::evm_coder::ERC165Call::INTERFACE_ID ||827						interface_id == Self::interface_id()828						#(829							|| #supports_interface830						)*831					)832				}833				pub fn generate_solidity_interface(tc: &evm_coder::solidity::TypeCollector, is_impl: bool) {834					use evm_coder::solidity::*;835					use core::fmt::Write;836					let interface = SolidityInterface {837						name: #solidity_name,838						selector: Self::interface_id(),839						is: &["Dummy", "ERC165", #(840							#solidity_is,841						)* #(842							#solidity_events_is,843						)* ],844						functions: (#(845							#solidity_functions,846						)*),847					};848					if is_impl {849						tc.collect("// Common stubs holder\ncontract Dummy {\n\tuint8 dummy;\n\tstring stub_error = \"this contract is implemented in native\";\n}\ncontract ERC165 is Dummy {\n\tfunction supportsInterface(bytes4 interfaceID) external view returns (bool) {\n\t\trequire(false, stub_error);\n\t\tinterfaceID;\n\t\treturn true;\n\t}\n}\n".into());850					} else {851						tc.collect("// Common stubs holder\ninterface Dummy {\n}\ninterface ERC165 is Dummy {\n\tfunction supportsInterface(bytes4 interfaceID) external view returns (bool);\n}\n".into());852					}853					#(854						#solidity_generators855					)*856					#(857						#solidity_event_generators858					)*859860					let mut out = string::new();861					// In solidity interface usage (is) should be preceeded by interface definition862					// This comment helps to sort it in a set863					if #solidity_name.starts_with("Inline") {864						out.push_str("// Inline\n");865					}866					let _ = interface.format(is_impl, &mut out, tc);867					tc.collect(out);868				}869			}870			impl #gen_ref ::evm_coder::Call for #call_name #gen_ref {871				fn parse(method_id: u32, reader: &mut ::evm_coder::abi::AbiReader) -> ::evm_coder::execution::Result<Option<Self>> {872					use ::evm_coder::abi::AbiRead;873					match method_id {874						::evm_coder::ERC165Call::INTERFACE_ID => return Ok(875							::evm_coder::ERC165Call::parse(method_id, reader)?876							.map(|c| Self::ERC165Call(c, ::core::marker::PhantomData))877						),878						#(879							#parsers,880						)*881						_ => {},882					}883					#(884						#call_parse885					)else*886					return Ok(None);887				}888			}889			impl #generics ::evm_coder::Weighted for #call_name #gen_ref {890				#[allow(unused_variables)]891				fn weight(&self) -> ::evm_coder::execution::DispatchInfo {892					match self {893						#(894							#weight_variants,895						)*896						// TODO: It should be very cheap, but not free897						Self::ERC165Call(::evm_coder::ERC165Call::SupportsInterface {..}, _) => 100u64.into(),898						#(899							#weight_variants_this,900						)*901					}902				}903			}904			impl #generics ::evm_coder::Callable<#call_name #gen_ref> for #name {905				#[allow(unreachable_code)] // In case of no inner calls906				fn call(&mut self, c: Msg<#call_name #gen_ref>) -> ::evm_coder::execution::ResultWithPostInfo<::evm_coder::abi::AbiWriter> {907					use ::evm_coder::abi::AbiWrite;908					match c.call {909						#(910							#call_variants,911						)*912						#call_name::ERC165Call(::evm_coder::ERC165Call::SupportsInterface {interface_id}, _) => {913							let mut writer = ::evm_coder::abi::AbiWriter::default();914							writer.bool(&<#call_name #gen_ref>::supports_interface(interface_id));915							return Ok(writer.into());916						}917						_ => {},918					}919					let mut writer = ::evm_coder::abi::AbiWriter::default();920					match c.call {921						#(922							#call_variants_this,923						)*924						_ => unreachable!()925					}926				}927			}928		}929	}930}