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 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94
extern crate proc_macro; use proc_macro::TokenStream; use quote::quote; use syn::parse::{Parse, ParseStream}; use syn::{parse_macro_input, Expr, Ident, Result, Token}; enum Arg { Item(Ident), ExprItem(Ident, Expr), } impl Parse for Arg { fn parse(input: ParseStream) -> Result<Self> { let ident: Ident = input.parse()?; let la = input.lookahead1(); if la.peek(Token![=]) { let _: Token![=] = input.parse()?; Ok(Arg::ExprItem(ident, input.parse()?)) } else { Ok(Arg::Item(ident)) } } } struct Args(Vec<Arg>); impl Args { fn clone_items(&self) -> impl Iterator<Item = &Ident> + '_ { self.0.iter().filter_map(|arg| { if let Arg::Item(ident) = arg { Some(ident) } else { None } }) } fn arbitrary_exprs(&self) -> impl Iterator<Item = (&Ident, &Expr)> + '_ { self.0.iter().filter_map(|arg| { if let Arg::ExprItem(ident, expr) = arg { Some((ident, expr)) } else { None } }) } } impl Parse for Args { fn parse(input: ParseStream) -> Result<Self> { if input.is_empty() { return Ok(Self(Vec::new())); } let terms = input.parse_terminated::<_, Token![,]>(Arg::parse)?; Ok(Self(terms.into_iter().collect())) } } #[proc_macro_attribute] pub fn closure_pass(args: TokenStream, input: TokenStream) -> TokenStream { let args = parse_macro_input!(args as Args); let input = parse_macro_input!(input as Expr); let clone_items = args .clone_items() .map(|ident| { quote! { let #ident = #ident.clone(); } }) .collect::<Vec<_>>(); let arbitrary_exprs = args .arbitrary_exprs() .map(|(ident, expr)| { quote! { let #ident = #expr; } }) .collect::<Vec<_>>(); let processed = quote! {{ #(#clone_items)* #(#arbitrary_exprs)* #input }}; TokenStream::from(processed) }