tlkit_expand/enumer/
getter.rs

1use proc_macro2::Span;
2use proc_macro2::TokenStream;
3use procmeta::prelude::*;
4use quote::format_ident;
5use quote::quote;
6use syn::Data;
7use syn::DataEnum;
8use syn::DeriveInput;
9use syn::Error;
10use syn::Field;
11use syn::Result;
12
13pub fn fn_impl_expand(props: Vec<Field>, data: &DataEnum) -> Result<TokenStream> {
14    if props.is_empty() {
15        return Ok(quote!());
16    }
17    let mut result_token = quote!();
18    let mut fn_tokens = vec![];
19    for field in props {
20        fn_tokens.push((field, quote!()));
21    }
22    for variant in &data.variants {
23        let mut values = vec![];
24        for attr in &variant.attrs {
25            let value_meta = attr.meta.require_list()?;
26            if !value_meta.path.is_ident("values") {
27                continue;
28            }
29            if !values.is_empty() {
30                return Err(Error::new(Span::call_site(), "duplicate define values"));
31            }
32            let mut parse_result = meta_list_to_expr(value_meta)?;
33            values.append(&mut parse_result);
34        }
35        if values.len() != fn_tokens.len() {
36            return Err(Error::new(
37                Span::call_site(),
38                "vaues's len not eq props's len",
39            ));
40        }
41
42        let var_ident = &variant.ident;
43        let match_branch_code = match &variant.fields {
44            syn::Fields::Named(named) => {
45                let mut fields = quote!();
46                for field in &named.named {
47                    let field_name = &field.ident;
48                    fields = quote!(#field_name,);
49                }
50                quote!(Self::#var_ident {#fields})
51            }
52            syn::Fields::Unnamed(unamed) => {
53                let mut fields = quote!();
54                for (index, _field) in unamed.unnamed.iter().enumerate() {
55                    let field_name = format_ident!("_{index}");
56                    fields = quote!(#field_name,);
57                }
58                quote!(Self::#var_ident (#fields))
59            }
60            syn::Fields::Unit => {
61                quote!(Self::#var_ident)
62            }
63        };
64        for (index, fn_token) in fn_tokens.iter_mut().enumerate() {
65            let value_token = &values[index];
66            let field_token = &fn_token.1;
67            fn_token.1 = quote! {
68                #field_token
69                #match_branch_code => #value_token.into(),
70            };
71        }
72    }
73    for (field, token) in fn_tokens {
74        let field_name = field
75            .ident
76            .as_ref()
77            .map(|t| t.to_string())
78            .unwrap_or_default();
79        let fn_name = format_ident!("get_{field_name}");
80        let ret_ty = field.ty;
81        result_token = quote! {
82            #result_token
83
84            pub fn #fn_name(&self) -> #ret_ty {
85                match self {
86                    #token
87                }
88            }
89        };
90    }
91    Ok(result_token)
92}
93
94pub fn expand(input: DeriveInput) -> Result<TokenStream> {
95    let ty = &input.ident;
96    let (impl_generics, ty_generics, where_clause) = input.generics.split_for_impl();
97    let result_token = match &input.data {
98        Data::Struct(_) => unimplemented!(),
99        Data::Enum(data) => {
100            let mut fields_named: Option<Vec<Field>> = None;
101            for attr in input.attrs {
102                let prop_meta = attr.meta.require_list()?;
103                if !prop_meta.path.is_ident("props") {
104                    continue;
105                }
106                if fields_named.is_some() {
107                    return Err(Error::new(Span::call_site(), "duplicate define props"));
108                }
109                let parse_result = meta_list_to_fields(prop_meta)?;
110                fields_named = Some(parse_result);
111            }
112            let fields = match fields_named {
113                Some(props) => props,
114                None => return Err(Error::new(Span::call_site(), "miss define values")),
115            };
116            let fn_tokens = fn_impl_expand(fields, data)?;
117            quote! {
118                impl #impl_generics #ty #ty_generics #where_clause {
119                    #fn_tokens
120                }
121            }
122        }
123        Data::Union(_) => unimplemented!(),
124    };
125    Ok(result_token)
126}