tlkit_expand/enumer/
getter.rs1use 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}