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}