1use std::result;23use proc_macro2::{TokenStream, Ident};4use quote::quote;5use syn::{6 Error, DeriveInput, Data, Attribute,7 parse::{Parse, ParseBuffer},8 spanned::Spanned,9 Expr, parenthesized,10};1112type Result<T = TokenStream, E = syn::Error> = result::Result<T, E>;1314fn parse_attr<A: Parse, I>(attrs: &[Attribute], ident: I) -> Result<Option<A>>15where16 Ident: PartialEq<I>,17{18 let attrs = attrs19 .iter()20 .filter(|a| a.path.is_ident(&ident))21 .collect::<Vec<_>>();22 if attrs.len() > 1 {23 return Err(Error::new(24 attrs[1].span(),25 "this attribute may be specified only once",26 ));27 } else if attrs.is_empty() {28 return Ok(None);29 }30 let attr = attrs[0];3132 let parsed = syn::parse2(attr.tokens.clone())?;33 Ok(Some(parsed))34}3536struct WeightAttr {37 handler: Expr,38}39impl Parse for WeightAttr {40 fn parse(input: &ParseBuffer) -> Result<Self> {41 let expr;42 parenthesized!(expr in input);43 let handler = Expr::parse(&expr)?;4445 Ok(Self { handler })46 }47}4849#[proc_macro_derive(PreDispatch, attributes(pre_dispatch, weight))]50pub fn derive_predispatch(item: proc_macro::TokenStream) -> proc_macro::TokenStream {51 fn inner(input: DeriveInput) -> Result {52 let (impl_generics, ty_generics, _where_clause) = input.generics.split_for_impl();53 let ident = &input.ident;54 let Data::Enum(data) = &input.data else {55 return Err(Error::new_spanned(input, "PreDispatch input is enum"));56 };5758 let matching = data59 .variants60 .iter()61 .map(|var| {62 let name = &var.ident;63 let handler = match &var.fields {64 syn::Fields::Named(named) => {65 if let Some(weight) = parse_attr::<WeightAttr, _>(&var.attrs, "weight")? {66 let weight = &weight.handler;67 let fields = named.named.iter().flat_map(|n| &n.ident);68 quote! {69 {#(#fields,)*} => {70 ::pallet_evm_coder_substrate::execution::DispatchInfo {71 weight: ::pallet_evm_coder_substrate::execution::Weight::from(#weight),72 }73 }74 }75 } else {76 quote! {77 {..} => {78 ::pallet_evm_coder_substrate::execution::DispatchInfo {79 weight: ::pallet_evm_coder_substrate::execution::Weight::zero()80 }81 }82 }83 }84 }85 syn::Fields::Unit => {86 if let Some(weight) = parse_attr::<WeightAttr, _>(&var.attrs, "weight")? {87 let weight = &weight.handler;88 quote! {89 => {90 ::pallet_evm_coder_substrate::execution::DispatchInfo {91 weight: ::pallet_evm_coder_substrate::execution::Weight::from(#weight),92 }93 }94 }95 } else {96 quote! {97 => {98 ::pallet_evm_coder_substrate::execution::DispatchInfo {99 weight: ::pallet_evm_coder_substrate::execution::Weight::zero()100 }101 }102 }103 }104 }105 syn::Fields::Unnamed(_) => {106 quote! {107 (call, ..) => {108 call.dispatch_info()109 }110 }111 }112 };113 Ok(quote! {114 Self::#name #handler,115 })116 })117 .collect::<Result>()?;118119 Ok(quote! {120 #[allow(unused_variables)]121 impl #impl_generics ::pallet_evm_coder_substrate::execution::PreDispatch for #ident #ty_generics where T: crate::Config {122 fn dispatch_info(&self) -> ::pallet_evm_coder_substrate::execution::DispatchInfo {123 match self {124 #matching125 }126 }127 }128 })129 }130 let item = syn::parse_macro_input!(item as DeriveInput);131 match inner(item) {132 Ok(o) => o.into(),133 Err(e) => e.into_compile_error().into(),134 }135}