kson_effect_param_macro/
lib.rs

1use proc_macro::TokenStream;
2use quote::quote;
3use syn::{parse_macro_input, Data, DeriveInput};
4
5#[proc_macro_derive(Effect)]
6pub fn derive_effect_param(input: TokenStream) -> TokenStream {
7    let input = parse_macro_input!(input as DeriveInput);
8
9    match &input.data {
10        Data::Enum(e) => {
11            let mut match_arms = vec![];
12            for variant in &e.variants {
13                let new_struct_expr = match &variant.fields {
14                    syn::Fields::Named(_) => todo!(),
15                    syn::Fields::Unnamed(_) => {
16                        let input = &input.ident;
17                        let variant = &variant.ident;
18                        quote!(#input::#variant(Effect::derive(&a,key,param)))
19                    }
20                    syn::Fields::Unit => panic!("Enum unit variants are not supported"),
21                };
22                let input = &input.ident;
23                let variant = &variant.ident;
24                match_arms.push(quote!(#input::#variant(a) => #new_struct_expr,));
25            }
26
27            match_arms.push(quote!(_ => panic!("Tried to derive from a different type"),));
28            let input = &input.ident;
29            proc_macro::TokenStream::from(quote!(
30                impl Effect for #input {
31                fn derive(&self, key: &str, param: &str) -> Self {
32                    match self { #(#match_arms)* }
33                }
34                fn param_list() -> &'static [&'static str] {
35                    &[]
36                }
37                }
38            ))
39        }
40        Data::Struct(s) => {
41            //self << other
42            let mut match_arms = vec![];
43            let mut fields = vec![];
44
45            for f in &s.fields {
46                if let Some(ident) = &f.ident {
47                    fields.push(quote!(stringify!(#ident)));
48                    match_arms.push(quote!(stringify!(#ident) => Self {
49                        #ident: param.parse().unwrap_or_default(),
50                        ..self.clone()
51                    },))
52                }
53            }
54
55            match_arms.push(quote!(_ => self.clone()));
56
57            let input = &input.ident;
58            proc_macro::TokenStream::from(quote!(
59            impl Effect for #input {
60                fn derive(&self, key: &str, param: &str) -> Self {
61                    match key {#(#match_arms)*}
62                }
63
64                fn param_list() -> &'static [&'static str]  {
65                    &[#(#fields),*]
66                }
67            }))
68        }
69        Data::Union(_) => panic!("Unions are not supported"),
70    }
71}