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

difftreelog

source

crates/evm-coder-macros/src/solidity_interface.rs22.7 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		match self {230			Self::Plain(v) if v == "value" => true,231			_ => false,232		}233	}234	fn is_caller(&self) -> bool {235		match self {236			Self::Plain(v) if v == "caller" => true,237			_ => false,238		}239	}240	fn is_special(&self) -> bool {241		self.is_caller() || self.is_value()242	}243	fn selector_ty_buf(&self, buf: &mut String) -> std::fmt::Result {244		match self {245			AbiType::Plain(t) => {246				write!(buf, "{}", t)247			}248			AbiType::Tuple(t) => {249				write!(buf, "(")?;250				for (i, t) in t.iter().enumerate() {251					if i != 0 {252						write!(buf, ",")?;253					}254					t.selector_ty_buf(buf)?;255				}256				write!(buf, ")")257			}258			AbiType::Vec(v) => {259				v.selector_ty_buf(buf)?;260				write!(buf, "[]")261			}262			AbiType::Array(v, len) => {263				v.selector_ty_buf(buf)?;264				write!(buf, "[{}]", len)265			}266		}267	}268	fn selector_ty(&self) -> String {269		let mut out = String::new();270		self.selector_ty_buf(&mut out).expect("no fmt error");271		out272	}273}274impl ToTokens for AbiType {275	fn to_tokens(&self, tokens: &mut proc_macro2::TokenStream) {276		match self {277			AbiType::Plain(t) => tokens.extend(quote! {#t}),278			AbiType::Tuple(t) => {279				tokens.extend(quote! {(280					#(#t),*281				)});282			}283			AbiType::Vec(v) => tokens.extend(quote! {Vec<#v>}),284			AbiType::Array(v, l) => tokens.extend(quote! {[#v; #l]}),285		}286	}287}288289struct MethodArg {290	name: Ident,291	camel_name: String,292	ty: AbiType,293}294impl MethodArg {295	fn try_from(value: &PatType) -> syn::Result<Self> {296		let name = parse_ident_from_pat(&value.pat)?.clone();297		Ok(Self {298			camel_name: cases::camelcase::to_camel_case(&name.to_string()),299			name,300			ty: AbiType::try_maybe_special_from(&value.ty)?,301		})302	}303	fn is_value(&self) -> bool {304		self.ty.is_value()305	}306	fn is_caller(&self) -> bool {307		self.ty.is_caller()308	}309	fn is_special(&self) -> bool {310		self.ty.is_special()311	}312	fn selector_ty(&self) -> String {313		assert!(!self.is_special());314		self.ty.selector_ty()315	}316317	fn expand_call_def(&self) -> proc_macro2::TokenStream {318		assert!(!self.is_special());319		let name = &self.name;320		let ty = &self.ty;321322		quote! {323			#name: #ty324		}325	}326327	fn expand_parse(&self) -> proc_macro2::TokenStream {328		assert!(!self.is_special());329		let name = &self.name;330		quote! {331			#name: reader.abi_read()?332		}333	}334335	fn expand_call_arg(&self) -> proc_macro2::TokenStream {336		if self.is_value() {337			quote! {338				c.value.clone()339			}340		} else if self.is_caller() {341			quote! {342				c.caller.clone()343			}344		} else {345			let name = &self.name;346			quote! {347				#name348			}349		}350	}351352	fn expand_solidity_argument(&self) -> proc_macro2::TokenStream {353		let camel_name = &self.camel_name.to_string();354		let ty = &self.ty;355		quote! {356			<NamedArgument<#ty>>::new(#camel_name)357		}358	}359}360361#[derive(PartialEq)]362enum Mutability {363	Mutable,364	View,365	Pure,366}367368pub struct WeightAttr(syn::Expr);369370mod keyword {371	syn::custom_keyword!(weight);372}373374impl syn::parse::Parse for WeightAttr {375	fn parse(input: syn::parse::ParseStream) -> syn::Result<Self> {376		input.parse::<syn::Token![#]>()?;377		let content;378		syn::bracketed!(content in input);379		content.parse::<keyword::weight>()?;380381		let weight_content;382		syn::parenthesized!(weight_content in content);383		Ok(WeightAttr(weight_content.parse::<syn::Expr>()?))384	}385}386387struct Method {388	name: Ident,389	camel_name: String,390	pascal_name: Ident,391	screaming_name: Ident,392	selector_str: String,393	selector: u32,394	args: Vec<MethodArg>,395	has_normal_args: bool,396	mutability: Mutability,397	result: Type,398	weight: Option<Expr>,399	docs: Vec<String>,400}401impl Method {402	fn try_from(value: &ImplItemMethod) -> syn::Result<Self> {403		let mut info = MethodInfo {404			rename_selector: None,405		};406		let mut docs = Vec::new();407		let mut weight = None;408		for attr in &value.attrs {409			let ident = parse_ident_from_path(&attr.path, false)?;410			if ident == "solidity" {411				let args = attr.parse_meta().unwrap();412				info = MethodInfo::from_meta(&args).unwrap();413			} else if ident == "doc" {414				let args = attr.parse_meta().unwrap();415				let value = match args {416					Meta::NameValue(MetaNameValue {417						lit: Lit::Str(str), ..418					}) => str.value(),419					_ => unreachable!(),420				};421				docs.push(value);422			} else if ident == "weight" {423				weight = Some(syn::parse2::<WeightAttr>(attr.to_token_stream())?.0);424			}425		}426		let ident = &value.sig.ident;427		let ident_str = ident.to_string();428		if !cases::snakecase::is_snake_case(&ident_str) {429			return Err(syn::Error::new(ident.span(), "method name should be snake_cased\nif alternative solidity name needs to be set - use #[solidity] attribute"));430		}431432		let mut mutability = Mutability::Pure;433434		if let Some(FnArg::Receiver(receiver)) = value435			.sig436			.inputs437			.iter()438			.find(|arg| matches!(arg, FnArg::Receiver(_)))439		{440			if receiver.reference.is_none() {441				return Err(syn::Error::new(442					receiver.span(),443					"receiver should be by ref",444				));445			}446			if receiver.mutability.is_some() {447				mutability = Mutability::Mutable;448			} else {449				mutability = Mutability::View;450			}451		}452		let mut args = Vec::new();453		for typ in value454			.sig455			.inputs456			.iter()457			.filter(|arg| matches!(arg, FnArg::Typed(_)))458		{459			let typ = match typ {460				FnArg::Typed(typ) => typ,461				_ => unreachable!(),462			};463			args.push(MethodArg::try_from(typ)?);464		}465466		if mutability != Mutability::Mutable && args.iter().any(|arg| arg.is_value()) {467			return Err(syn::Error::new(468				args.iter().find(|arg| arg.is_value()).unwrap().ty.span(),469				"payable function should be mutable",470			));471		}472473		let result = match &value.sig.output {474			ReturnType::Type(_, ty) => ty,475			_ => 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)")),476		};477		let result = parse_result_ok(result)?;478479		let camel_name = info480			.rename_selector481			.unwrap_or_else(|| cases::camelcase::to_camel_case(&ident.to_string()));482		let mut selector_str = camel_name.clone();483		selector_str.push('(');484		let mut has_normal_args = false;485		for (i, arg) in args.iter().filter(|arg| !arg.is_special()).enumerate() {486			if i != 0 {487				selector_str.push(',');488			}489			write!(selector_str, "{}", arg.selector_ty()).unwrap();490			has_normal_args = true;491		}492		selector_str.push(')');493		let selector = fn_selector_str(&selector_str);494495		Ok(Self {496			name: ident.clone(),497			camel_name,498			pascal_name: snake_ident_to_pascal(ident),499			screaming_name: snake_ident_to_screaming(ident),500			selector_str,501			selector,502			args,503			has_normal_args,504			mutability,505			result: result.clone(),506			weight,507			docs,508		})509	}510	fn expand_call_def(&self) -> proc_macro2::TokenStream {511		let defs = self512			.args513			.iter()514			.filter(|a| !a.is_special())515			.map(|a| a.expand_call_def());516		let pascal_name = &self.pascal_name;517518		if self.has_normal_args {519			quote! {520				#pascal_name {521					#(522						#defs,523					)*524				}525			}526		} else {527			quote! {#pascal_name}528		}529	}530531	fn expand_const(&self) -> proc_macro2::TokenStream {532		let screaming_name = &self.screaming_name;533		let selector = self.selector;534		let selector_str = &self.selector_str;535		quote! {536			#[doc = #selector_str]537			const #screaming_name: u32 = #selector;538		}539	}540541	fn expand_interface_id(&self) -> proc_macro2::TokenStream {542		let screaming_name = &self.screaming_name;543		quote! {544			interface_id ^= Self::#screaming_name;545		}546	}547548	fn expand_parse(&self) -> proc_macro2::TokenStream {549		let pascal_name = &self.pascal_name;550		let screaming_name = &self.screaming_name;551		if self.has_normal_args {552			let parsers = self553				.args554				.iter()555				.filter(|a| !a.is_special())556				.map(|a| a.expand_parse());557			quote! {558				Self::#screaming_name => return Ok(Some(Self::#pascal_name {559					#(560						#parsers,561					)*562				}))563			}564		} else {565			quote! { Self::#screaming_name => return Ok(Some(Self::#pascal_name)) }566		}567	}568569	fn expand_variant_call(&self, call_name: &proc_macro2::Ident) -> proc_macro2::TokenStream {570		let pascal_name = &self.pascal_name;571		let name = &self.name;572573		let matcher = if self.has_normal_args {574			let names = self575				.args576				.iter()577				.filter(|a| !a.is_special())578				.map(|a| &a.name);579580			quote! {{581				#(582					#names,583				)*584			}}585		} else {586			quote! {}587		};588589		let receiver = match self.mutability {590			Mutability::Mutable | Mutability::View => quote! {self.},591			Mutability::Pure => quote! {Self::},592		};593		let args = self.args.iter().map(|a| a.expand_call_arg());594595		quote! {596			#call_name::#pascal_name #matcher => {597				let result = #receiver #name(598					#(599						#args,600					)*601				)?;602				(&result).into_result()603			}604		}605	}606607	fn expand_variant_weight(&self) -> proc_macro2::TokenStream {608		let pascal_name = &self.pascal_name;609		if let Some(weight) = &self.weight {610			let matcher = if self.has_normal_args {611				let names = self612					.args613					.iter()614					.filter(|a| !a.is_special())615					.map(|a| &a.name);616617				quote! {{618					#(619						#names,620					)*621				}}622			} else {623				quote! {}624			};625			quote! {626				Self::#pascal_name #matcher => (#weight).into()627			}628		} else {629			let matcher = if self.has_normal_args {630				quote! {{..}}631			} else {632				quote! {}633			};634			quote! {635				Self::#pascal_name #matcher => ().into()636			}637		}638	}639640	fn expand_solidity_function(&self) -> proc_macro2::TokenStream {641		let camel_name = &self.camel_name;642		let mutability = match self.mutability {643			Mutability::Mutable => quote! {SolidityMutability::Mutable},644			Mutability::View => quote! { SolidityMutability::View },645			Mutability::Pure => quote! {SolidityMutability::Pure},646		};647		let result = &self.result;648649		let args = self650			.args651			.iter()652			.filter(|a| !a.is_special())653			.map(MethodArg::expand_solidity_argument);654		let docs = self.docs.iter();655		let selector = format!("{} {:0>8x}", self.selector_str, self.selector);656657		quote! {658			SolidityFunction {659				docs: &[#(#docs),*],660				selector: #selector,661				name: #camel_name,662				mutability: #mutability,663				args: (664					#(665						#args,666					)*667				),668				result: <UnnamedArgument<#result>>::default(),669			}670		}671	}672}673674fn generics_list(gen: &Generics) -> proc_macro2::TokenStream {675	if gen.params.is_empty() {676		return quote! {};677	}678	let params = gen.params.iter().map(|p| match p {679		syn::GenericParam::Type(id) => {680			let v = &id.ident;681			quote! {#v}682		}683		syn::GenericParam::Lifetime(lt) => {684			let v = &lt.lifetime;685			quote! {#v}686		}687		syn::GenericParam::Const(c) => {688			let i = &c.ident;689			quote! {#i}690		}691	});692	quote! { #(#params),* }693}694fn generics_reference(gen: &Generics) -> proc_macro2::TokenStream {695	if gen.params.is_empty() {696		return quote! {};697	}698	let list = generics_list(gen);699	quote! { <#list> }700}701fn generics_data(gen: &Generics) -> proc_macro2::TokenStream {702	let list = generics_list(gen);703	if gen.params.len() == 1 {704		quote! {#list}705	} else {706		quote! { (#list) }707	}708}709710pub struct SolidityInterface {711	generics: Generics,712	name: Box<syn::Type>,713	info: InterfaceInfo,714	methods: Vec<Method>,715}716impl SolidityInterface {717	pub fn try_from(info: InterfaceInfo, value: &ItemImpl) -> syn::Result<Self> {718		let mut methods = Vec::new();719720		for item in &value.items {721			if let ImplItem::Method(method) = item {722				methods.push(Method::try_from(method)?)723			}724		}725		Ok(Self {726			generics: value.generics.clone(),727			name: value.self_ty.clone(),728			info,729			methods,730		})731	}732	pub fn expand(self) -> proc_macro2::TokenStream {733		let name = self.name;734735		let solidity_name = self.info.name.to_string();736		let call_name = pascal_ident_to_call(&self.info.name);737		let generics = self.generics;738		let gen_ref = generics_reference(&generics);739		let gen_data = generics_data(&generics);740741		let call_sub = self742			.info743			.inline_is744			.0745			.iter()746			.chain(self.info.is.0.iter())747			.map(|c| Is::expand_call_def(c, &gen_ref));748		let call_parse = self749			.info750			.inline_is751			.0752			.iter()753			.chain(self.info.is.0.iter())754			.map(|is| Is::expand_parse(is, &gen_ref));755		let call_variants = self756			.info757			.inline_is758			.0759			.iter()760			.chain(self.info.is.0.iter())761			.map(|c| Is::expand_variant_call(c, &call_name, &gen_ref));762		let weight_variants = self763			.info764			.inline_is765			.0766			.iter()767			.chain(self.info.is.0.iter())768			.map(Is::expand_variant_weight);769770		let inline_interface_id = self.info.inline_is.0.iter().map(Is::expand_interface_id);771		let supports_interface = self772			.info773			.is774			.0775			.iter()776			.map(|is| Is::expand_supports_interface(is, &gen_ref));777778		let calls = self.methods.iter().map(Method::expand_call_def);779		let consts = self.methods.iter().map(Method::expand_const);780		let interface_id = self.methods.iter().map(Method::expand_interface_id);781		let parsers = self.methods.iter().map(Method::expand_parse);782		let call_variants_this = self783			.methods784			.iter()785			.map(|m| Method::expand_variant_call(m, &call_name));786		let weight_variants_this = self.methods.iter().map(Method::expand_variant_weight);787		let solidity_functions = self.methods.iter().map(Method::expand_solidity_function);788789		// TODO: Inline inline_is790		let solidity_is = self791			.info792			.is793			.0794			.iter()795			.chain(self.info.inline_is.0.iter())796			.map(|is| is.name.to_string());797		let solidity_events_is = self.info.events.0.iter().map(|is| is.name.to_string());798		let solidity_generators = self799			.info800			.is801			.0802			.iter()803			.chain(self.info.inline_is.0.iter())804			.map(|is| Is::expand_generator(is, &gen_ref));805		let solidity_event_generators = self.info.events.0.iter().map(Is::expand_event_generator);806807		// let methods = self.methods.iter().map(Method::solidity_def);808809		quote! {810			#[derive(Debug)]811			pub enum #call_name #gen_ref {812				ERC165Call(::evm_coder::ERC165Call, ::core::marker::PhantomData<#gen_data>),813				#(814					#calls,815				)*816				#(817					#call_sub,818				)*819			}820			impl #gen_ref #call_name #gen_ref {821				#(822					#consts823				)*824				pub fn interface_id() -> u32 {825					let mut interface_id = 0;826					#(#interface_id)*827					#(#inline_interface_id)*828					interface_id829				}830				pub fn supports_interface(interface_id: u32) -> bool {831					interface_id != 0xffffff && (832						interface_id == ::evm_coder::ERC165Call::INTERFACE_ID ||833						interface_id == Self::interface_id()834						#(835							|| #supports_interface836						)*837					)838				}839				pub fn generate_solidity_interface(tc: &evm_coder::solidity::TypeCollector, is_impl: bool) {840					use evm_coder::solidity::*;841					use core::fmt::Write;842					let interface = SolidityInterface {843						name: #solidity_name,844						selector: Self::interface_id(),845						is: &["Dummy", "ERC165", #(846							#solidity_is,847						)* #(848							#solidity_events_is,849						)* ],850						functions: (#(851							#solidity_functions,852						)*),853					};854					if is_impl {855						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());856					} else {857						tc.collect("// Common stubs holder\ninterface Dummy {\n}\ninterface ERC165 is Dummy {\n\tfunction supportsInterface(bytes4 interfaceID) external view returns (bool);\n}\n".into());858					}859					#(860						#solidity_generators861					)*862					#(863						#solidity_event_generators864					)*865866					let mut out = string::new();867					// In solidity interface usage (is) should be preceeded by interface definition868					// This comment helps to sort it in a set869					if #solidity_name.starts_with("Inline") {870						out.push_str("// Inline\n");871					}872					let _ = interface.format(is_impl, &mut out, tc);873					tc.collect(out);874				}875			}876			impl #gen_ref ::evm_coder::Call for #call_name #gen_ref {877				fn parse(method_id: u32, reader: &mut ::evm_coder::abi::AbiReader) -> ::evm_coder::execution::Result<Option<Self>> {878					use ::evm_coder::abi::AbiRead;879					match method_id {880						::evm_coder::ERC165Call::INTERFACE_ID => return Ok(881							::evm_coder::ERC165Call::parse(method_id, reader)?882							.map(|c| Self::ERC165Call(c, ::core::marker::PhantomData))883						),884						#(885							#parsers,886						)*887						_ => {},888					}889					#(890						#call_parse891					)else*892					return Ok(None);893				}894			}895			impl #generics ::evm_coder::Weighted for #call_name #gen_ref {896				#[allow(unused_variables)]897				fn weight(&self) -> ::evm_coder::execution::DispatchInfo {898					match self {899						#(900							#weight_variants,901						)*902						// TODO: It should be very cheap, but not free903						Self::ERC165Call(::evm_coder::ERC165Call::SupportsInterface {..}, _) => 100u64.into(),904						#(905							#weight_variants_this,906						)*907					}908				}909			}910			impl #generics ::evm_coder::Callable<#call_name #gen_ref> for #name {911				#[allow(unreachable_code)] // In case of no inner calls912				fn call(&mut self, c: Msg<#call_name #gen_ref>) -> ::evm_coder::execution::ResultWithPostInfo<::evm_coder::abi::AbiWriter> {913					use ::evm_coder::abi::AbiWrite;914					match c.call {915						#(916							#call_variants,917						)*918						#call_name::ERC165Call(::evm_coder::ERC165Call::SupportsInterface {interface_id}, _) => {919							let mut writer = ::evm_coder::abi::AbiWriter::default();920							writer.bool(&<#call_name #gen_ref>::supports_interface(interface_id));921							return Ok(writer.into());922						}923						_ => {},924					}925					let mut writer = ::evm_coder::abi::AbiWriter::default();926					match c.call {927						#(928							#call_variants_this,929						)*930						_ => unreachable!()931					}932				}933			}934		}935	}936}