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 140 Plain(Ident),141 142 Tuple(Vec<AbiType>),143 144 Vec(Box<AbiType>),145 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 = <.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 790 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 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 868 869 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 903 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)] 912 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}