zng_var_proc_macros/
merge_var.rs

1use syn::{
2    Expr, Path, Token,
3    parse::{Parse, ParseStream},
4    parse_macro_input,
5    punctuated::Punctuated,
6};
7
8pub fn expand(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
9    let Input { vars_mod, mut inputs, .. } = parse_macro_input!(input as Input);
10
11    if inputs.len() < 3 {
12        abort_call_site!("expected at least two input vars and one merge closure")
13    }
14
15    let merge = inputs.pop().unwrap();
16
17    let type_idents: Vec<_> = (0..inputs.len()).map(|i| ident!("T{i}")).collect();
18    let var_idents: Vec<_> = (0..inputs.len()).map(|i| ident!("V{i}")).collect();
19    let input_idents: Vec<_> = (0..inputs.len()).map(|i| ident!("var{i}")).collect();
20    let idx: Vec<_> = (0..inputs.len())
21        .map(|i| syn::Index {
22            index: i as _,
23            span: proc_macro2::Span::call_site(),
24        })
25        .collect();
26
27    let out = quote! {
28        {
29            #[inline(always)]
30            fn merge_var__<
31                #(#type_idents: #vars_mod::VarValue,)*
32                #(#var_idents: #vars_mod::Var<#type_idents>,)*
33                O: #vars_mod::VarValue,
34                F: FnMut(
35                    #(&#type_idents,)*
36                ) -> O + Send + 'static
37            >(
38                #(#input_idents: #var_idents,)*
39                mut merge: F
40            ) -> #vars_mod::BoxedVar<O> {
41                let input_types = (
42                    #(#vars_mod::types::ArcMergeVarInput::new(&#input_idents)),*
43                );
44                #vars_mod::types::ArcMergeVar::new(
45                    Box::new([
46                        #(Box::new(#input_idents),)*
47                    ]),
48                    move |inputs| {
49                        merge(
50                            #(input_types.#idx.get(&inputs[#idx])),*
51                        )
52                    }
53                )
54            }
55            merge_var__(#inputs #merge)
56        }
57    };
58
59    out.into()
60}
61
62struct Input {
63    vars_mod: Path,
64    _comma: Token![,],
65    inputs: Punctuated<Expr, Token![,]>,
66}
67impl Parse for Input {
68    fn parse(input: ParseStream) -> syn::Result<Self> {
69        Ok(Input {
70            vars_mod: input.parse()?,
71            _comma: input.parse()?,
72            inputs: Punctuated::parse_terminated(input)?,
73        })
74    }
75}