1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53
extern crate proc_macro; use proc_macro::TokenStream; use syn::*; use quote::quote; fn get_fn_info( func: &ItemFn, args: AttributeArgs, ) -> (&Vec<Attribute>, &Visibility, &Signature, Vec<u32>, &Block) { let signature = &func.sig; let function_body = &func.block; let attributes = &func.attrs; let visibility = &func.vis; let versions: Vec<u32> = args .into_iter() .map(|item| { if let NestedMeta::Lit(lit) = item { if let Lit::Int(lit_int) = lit { lit_int .base10_parse::<u32>() .expect("couldn't parse version") } else { panic!("Invalid version token: {:?}", lit); } } else { panic!("Invalid version token: {:?}", item); } }) .collect(); (attributes, visibility, signature, versions, function_body) } #[proc_macro_attribute] pub fn bolt_version(attr_args: TokenStream, item: TokenStream) -> TokenStream { let func = syn::parse_macro_input!(item as syn::ItemFn); let args = syn::parse_macro_input!(attr_args as syn::AttributeArgs); let (attributes, visibility, signature, versions, function_body) = get_fn_info(&func, args); quote!( #(#attributes)* #visibility #signature { if self.version.is_some() && [#(#versions),*].contains(&self.version.unwrap()) { #function_body } else { Err(crate::error::Error::UnsupportedOperation(self.version)) } } ) .into() }