procmeta_core/expand/
token.rs

1use proc_macro2::{Span, TokenStream};
2use quote::{format_ident, quote};
3use syn::{Data, DeriveInput, Fields, LitInt};
4
5pub fn expand(input: DeriveInput) -> TokenStream {
6    let ty = input.ident;
7    let (impl_generics, ty_generics, where_clause) = input.generics.split_for_impl();
8    let mut result_token = quote!();
9    match &input.data {
10        Data::Struct(data) => match &data.fields {
11            syn::Fields::Named(named) => {
12                let mut let_token = quote!();
13                let mut inner_token = quote!();
14                for field in named.named.iter() {
15                    let field_ident = &field.ident;
16                    let_token = quote! {
17                        #let_token
18                        let #field_ident = self.#field_ident.get_token_stream();
19                    };
20                    inner_token = quote! {
21                        #inner_token
22                        #field_ident: ##field_ident,
23                    };
24                }
25                result_token = quote! {
26                    #let_token
27                    quote!(#ty {
28                        #inner_token
29                    })
30                };
31            }
32            syn::Fields::Unnamed(unamed) => {
33                let mut let_token = quote!();
34                let mut inner_token = quote!();
35                for (index, _field) in unamed.unnamed.iter().enumerate() {
36                    let field_ident = format_ident!("field_{}", index);
37                    let index = LitInt::new(&index.to_string(), Span::call_site());
38                    let value_token = quote!(self. #index.get_token_stream());
39                    let_token = quote! {
40                        #let_token
41                        let #field_ident = #value_token;
42                    };
43                    inner_token = quote! {
44                        #inner_token
45                        ##field_ident,
46                    };
47                }
48                result_token = quote! {
49                    #let_token
50                    quote!(#ty (
51                        #inner_token
52                    ))
53                };
54            }
55            syn::Fields::Unit => {
56                result_token = quote! {
57                    quote!(#ty)
58                };
59            }
60        },
61        Data::Enum(enumer) => {
62            for variant in &enumer.variants {
63                let variant_token;
64                let variant_ident = &variant.ident;
65                let mut pat = quote!();
66                match &variant.fields {
67                    Fields::Named(named) => {
68                        let mut let_token = quote!();
69                        let mut inner_token = quote!();
70                        for field in named.named.iter() {
71                            let field_ident = &field.ident;
72                            pat = quote! {#pat #field_ident,};
73                            let_token = quote! {
74                                #let_token
75                                let #field_ident = #field_ident.get_token_stream();
76                            };
77                            inner_token = quote! {
78                                #inner_token
79                                #field_ident: ##field_ident,
80                            };
81                        }
82                        pat = quote! {{#pat}};
83
84                        variant_token = quote! {
85                            #let_token
86                            quote!(#ty :: #variant_ident {
87                                #inner_token
88                            })
89                        };
90                    }
91                    Fields::Unnamed(unamed) => {
92                        let mut let_token = quote!();
93                        let mut inner_token = quote!();
94                        for (index, _field) in unamed.unnamed.iter().enumerate() {
95                            let field_ident = format_ident!("field_{}", index);
96                            pat = quote! {#pat #field_ident,};
97                            let value_token = quote!(#field_ident.get_token_stream());
98                            let_token = quote! {
99                                #let_token
100                                let #field_ident = #value_token;
101                            };
102                            inner_token = quote! {
103                                #inner_token
104                                ##field_ident,
105                            };
106                        }
107                        pat = quote! {(#pat)};
108
109                        variant_token = quote! {
110                            #let_token
111                            quote!(#ty :: #variant_ident (
112                                #inner_token
113                            ))
114                        };
115                    }
116                    Fields::Unit => {
117                        pat = quote!();
118                        variant_token = quote! {
119                            quote!(#ty :: #variant_ident)
120                        };
121                    }
122                }
123                result_token = quote! {
124                    #result_token
125                    #ty ::#variant_ident #pat => {
126                        #variant_token
127                    }
128                }
129            }
130            result_token = quote! {
131                match self {
132                    #result_token
133                }
134            };
135        }
136        Data::Union(_) => unimplemented!(),
137    }
138    quote! {
139        impl #impl_generics GetTokenStream for #ty #ty_generics #where_clause {
140
141            fn get_token_stream(self) -> TokenStream {
142                #result_token
143            }
144
145            fn get_self_ty() -> TokenStream {
146                quote!(#ty)
147            }
148        }
149    }
150}