1extern crate proc_macro;
2
3use proc_macro::TokenStream;
4use quote::quote;
5use syn::parse::{Parse, ParseStream};
6use syn::{parse_macro_input, Expr, Ident, Result, Token};
7
8enum Arg {
9 Item(Ident),
10 ExprItem(Ident, Expr),
11}
12
13impl Parse for Arg {
14 fn parse(input: ParseStream) -> Result<Self> {
15 let ident: Ident = input.parse()?;
16
17 let la = input.lookahead1();
18
19 if la.peek(Token![=]) {
20 let _: Token![=] = input.parse()?;
21 Ok(Arg::ExprItem(ident, input.parse()?))
22 } else {
23 Ok(Arg::Item(ident))
24 }
25 }
26}
27
28struct Args(Vec<Arg>);
29
30impl Args {
31 fn clone_items(&self) -> impl Iterator<Item = &Ident> + '_ {
32 self.0.iter().filter_map(|arg| {
33 if let Arg::Item(ident) = arg {
34 Some(ident)
35 } else {
36 None
37 }
38 })
39 }
40
41 fn arbitrary_exprs(&self) -> impl Iterator<Item = (&Ident, &Expr)> + '_ {
42 self.0.iter().filter_map(|arg| {
43 if let Arg::ExprItem(ident, expr) = arg {
44 Some((ident, expr))
45 } else {
46 None
47 }
48 })
49 }
50}
51
52impl Parse for Args {
53 fn parse(input: ParseStream) -> Result<Self> {
54 if input.is_empty() {
55 return Ok(Self(Vec::new()));
56 }
57
58 let terms = input.parse_terminated::<_, Token![,]>(Arg::parse)?;
59
60 Ok(Self(terms.into_iter().collect()))
61 }
62}
63
64#[proc_macro_attribute]
65pub fn closure_pass(args: TokenStream, input: TokenStream) -> TokenStream {
66 let args = parse_macro_input!(args as Args);
67 let input = parse_macro_input!(input as Expr);
68
69 let clone_items = args
70 .clone_items()
71 .map(|ident| {
72 quote! {
73 let #ident = #ident.clone();
74 }
75 })
76 .collect::<Vec<_>>();
77
78 let arbitrary_exprs = args
79 .arbitrary_exprs()
80 .map(|(ident, expr)| {
81 quote! {
82 let #ident = #expr;
83 }
84 })
85 .collect::<Vec<_>>();
86
87 let processed = quote! {{
88 #(#clone_items)*
89 #(#arbitrary_exprs)*
90 #input
91 }};
92
93 TokenStream::from(processed)
94}