zng_var_proc_macros/
when_var.rs

1use syn::{
2    Attribute, Expr, Path, Token, parenthesized,
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 {
10        vars_mod,
11        conditions,
12        default:
13            DefaultArm {
14                attrs: default_attrs,
15                use_macro: default_use_macro,
16                value: default_value,
17                ..
18            },
19        ..
20    } = parse_macro_input!(input as Input);
21
22    // start builder
23    let mut out = quote! {
24        #(#default_attrs)*
25        let mut __b = #vars_mod::types::WhenVarBuilder::new(#default_value);
26    };
27
28    if let Some(m) = default_use_macro {
29        let m = m.path;
30        out = quote! {
31            #m! {
32                #out
33            }
34        };
35    }
36
37    // add conditions
38    for ConditionArm {
39        attrs,
40        use_macro,
41        condition,
42        value,
43        ..
44    } in conditions
45    {
46        let mut arm = quote! {
47            #(#attrs)*
48            __b.push(#condition, #value);
49        };
50
51        if let Some(m) = use_macro {
52            let m = m.path;
53            arm = quote! {
54                #m! {
55                    #arm
56                }
57            };
58        }
59
60        out.extend(arm);
61    }
62
63    // build
64    out = quote! {
65        {
66            #out
67            __b.build()
68        }
69    };
70
71    out.into()
72}
73
74struct Input {
75    vars_mod: Path,
76    conditions: Punctuated<ConditionArm, Token![,]>,
77    default: DefaultArm,
78    _trailing_comma: Option<Token![,]>,
79}
80impl Parse for Input {
81    fn parse(input: ParseStream) -> syn::Result<Self> {
82        let vars_mod = input.parse()?;
83        let mut conditions = Punctuated::new();
84        while !input.peek(Token![_]) {
85            conditions.push(input.parse()?);
86            conditions.push_punct(input.parse()?);
87        }
88        Ok(Input {
89            vars_mod,
90            conditions,
91            default: input.parse()?,
92            _trailing_comma: input.parse()?,
93        })
94    }
95}
96
97struct ConditionArm {
98    attrs: Vec<Attribute>,
99    use_macro: Option<UseMacro>,
100    condition: Expr,
101    _fat_arrow_token: Token![=>],
102    value: Expr,
103}
104impl Parse for ConditionArm {
105    fn parse(input: ParseStream) -> syn::Result<Self> {
106        Ok(ConditionArm {
107            attrs: Attribute::parse_outer(input)?,
108            use_macro: if input.peek(Token![use]) { Some(input.parse()?) } else { None },
109            condition: input.parse()?,
110            _fat_arrow_token: input.parse()?,
111            value: input.parse()?,
112        })
113    }
114}
115
116struct DefaultArm {
117    attrs: Vec<Attribute>,
118    use_macro: Option<UseMacro>,
119    _wild_token: Token![_],
120    _fat_arrow_token: Token![=>],
121    value: Expr,
122}
123impl Parse for DefaultArm {
124    fn parse(input: ParseStream) -> syn::Result<Self> {
125        Ok(DefaultArm {
126            attrs: Attribute::parse_outer(input)?,
127            use_macro: if input.peek(Token![use]) { Some(input.parse()?) } else { None },
128            _wild_token: input.parse()?,
129            _fat_arrow_token: input.parse()?,
130            value: input.parse()?,
131        })
132    }
133}
134
135struct UseMacro {
136    path: Path,
137}
138impl Parse for UseMacro {
139    fn parse(input: ParseStream) -> syn::Result<Self> {
140        let _: Token![use] = input.parse()?;
141        let inner;
142        let _ = parenthesized!(inner in input);
143        Ok(UseMacro { path: inner.parse()? })
144    }
145}