1use crate::add_trait_bounds;
2use crate::context::{Context, Tokens};
3use proc_macro2::TokenStream;
4use quote::{quote, quote_spanned};
5use syn::spanned::Spanned as _;
6
7pub struct Derive {
9 input: syn::DeriveInput,
10}
11
12impl syn::parse::Parse for Derive {
13 fn parse(input: syn::parse::ParseStream) -> syn::Result<Self> {
14 Ok(Self {
15 input: input.parse()?,
16 })
17 }
18}
19
20impl Derive {
21 pub(super) fn expand(self, cx: &Context) -> Result<TokenStream, ()> {
22 let tokens = cx.tokens_with_module(None);
23
24 let mut expander = Expander { cx, tokens };
25
26 match &self.input.data {
27 syn::Data::Struct(st) => {
28 if let Ok(stream) = expander.expand_struct(&self.input, st) {
29 return Ok(stream);
30 }
31 }
32 syn::Data::Enum(en) => {
33 if let Ok(stream) = expander.expand_enum(&self.input, en) {
34 return Ok(stream);
35 }
36 }
37 syn::Data::Union(un) => {
38 expander.cx.error(syn::Error::new_spanned(
39 un.union_token,
40 "not supported on unions",
41 ));
42 }
43 }
44
45 Err(())
46 }
47}
48
49struct Expander<'cx> {
50 cx: &'cx Context,
51 tokens: Tokens,
52}
53
54impl Expander<'_> {
55 fn expand_struct(
57 &mut self,
58 input: &syn::DeriveInput,
59 st: &syn::DataStruct,
60 ) -> Result<TokenStream, ()> {
61 _ = self.cx.type_attrs(&input.attrs);
62 self.expand_struct_fields(input, &st.fields)
63 }
64
65 fn expand_enum(
67 &mut self,
68 input: &syn::DeriveInput,
69 st: &syn::DataEnum,
70 ) -> Result<TokenStream, ()> {
71 _ = self.cx.type_attrs(&input.attrs);
72
73 let mut impl_into_tokens = Vec::new();
74
75 for variant in &st.variants {
76 let expanded = self.expand_variant_fields(variant, &variant.fields)?;
77 impl_into_tokens.push(expanded);
78 }
79
80 let ident = &input.ident;
81 let Tokens {
82 to_tokens,
83 macro_context,
84 token_stream,
85 alloc,
86 ..
87 } = &self.tokens;
88
89 let mut generics = input.generics.clone();
90
91 add_trait_bounds(&mut generics, to_tokens);
92
93 let (impl_generics, type_generics, where_generics) = generics.split_for_impl();
94
95 Ok(quote! {
96 #[automatically_derived]
97 impl #impl_generics #to_tokens for #ident #type_generics #where_generics {
98 fn to_tokens(&self, context: &mut #macro_context, stream: &mut #token_stream) -> #alloc::Result<()> {
99 match self {
100 #(#impl_into_tokens),*
101 }
102
103 Ok(())
104 }
105 }
106 })
107 }
108
109 fn expand_struct_fields(
111 &mut self,
112 input: &syn::DeriveInput,
113 fields: &syn::Fields,
114 ) -> Result<TokenStream, ()> {
115 match fields {
116 syn::Fields::Named(named) => self.expand_struct_named(input, named),
117 syn::Fields::Unnamed(..) => {
118 self.cx.error(syn::Error::new_spanned(
119 fields,
120 "tuple structs are not supported",
121 ));
122 Err(())
123 }
124 syn::Fields::Unit => {
125 self.cx.error(syn::Error::new_spanned(
126 fields,
127 "unit structs are not supported",
128 ));
129 Err(())
130 }
131 }
132 }
133
134 fn expand_variant_fields(
136 &mut self,
137 variant: &syn::Variant,
138 fields: &syn::Fields,
139 ) -> Result<TokenStream, ()> {
140 match fields {
141 syn::Fields::Named(named) => self.expand_variant_named(variant, named),
142 syn::Fields::Unnamed(unnamed) => self.expand_variant_unnamed(variant, unnamed),
143 syn::Fields::Unit => Ok(self.expand_variant_unit(variant)),
144 }
145 }
146
147 fn expand_struct_named(
149 &mut self,
150 input: &syn::DeriveInput,
151 named: &syn::FieldsNamed,
152 ) -> Result<TokenStream, ()> {
153 let mut fields = Vec::new();
154
155 let Tokens {
156 to_tokens,
157 macro_context,
158 token_stream,
159 alloc,
160 ..
161 } = &self.tokens;
162
163 for field in &named.named {
164 let ident = self.cx.field_ident(field)?;
165 let attrs = self.cx.field_attrs(&field.attrs);
166
167 if attrs.skip() {
168 continue;
169 }
170
171 fields.push(quote! { #to_tokens::to_tokens(&self.#ident, context, stream)? })
172 }
173
174 let ident = &input.ident;
175
176 let mut generics = input.generics.clone();
177
178 add_trait_bounds(&mut generics, to_tokens);
179
180 let (impl_generics, type_generics, where_generics) = generics.split_for_impl();
181
182 let into_tokens_impl = quote_spanned! { named.span() =>
183 #[automatically_derived]
184 impl #impl_generics #to_tokens for #ident #type_generics #where_generics {
185 fn to_tokens(&self, context: &mut #macro_context, stream: &mut #token_stream) -> #alloc::Result<()> {
186 #(#fields;)*
187 Ok(())
188 }
189 }
190 };
191
192 Ok(quote_spanned! { named.span() =>
193 #into_tokens_impl
194 })
195 }
196
197 fn expand_variant_named(
199 &mut self,
200 variant: &syn::Variant,
201 named: &syn::FieldsNamed,
202 ) -> Result<TokenStream, ()> {
203 let mut fields = Vec::new();
204 let mut idents = Vec::new();
205
206 let Tokens { to_tokens, .. } = &self.tokens;
207
208 for field in &named.named {
209 let ident = self.cx.field_ident(field)?;
210 let attrs = self.cx.field_attrs(&field.attrs);
211 idents.push(ident);
212
213 if attrs.skip() {
214 continue;
215 }
216
217 fields.push(quote! { #to_tokens::to_tokens(&#ident, context, stream)? })
218 }
219
220 let ident = &variant.ident;
221
222 Ok(quote! {
223 Self::#ident { #(#idents,)* } => { #(#fields;)* }
224 })
225 }
226
227 fn expand_variant_unnamed(
229 &mut self,
230 variant: &syn::Variant,
231 named: &syn::FieldsUnnamed,
232 ) -> Result<TokenStream, ()> {
233 let mut field_into_tokens = Vec::new();
234 let mut idents = Vec::new();
235
236 let Tokens { to_tokens, .. } = &self.tokens;
237
238 for (n, field) in named.unnamed.iter().enumerate() {
239 let ident = syn::Ident::new(&format!("f{}", n), field.span());
240 let attrs = self.cx.field_attrs(&field.attrs);
241
242 idents.push(ident.clone());
243
244 if attrs.skip() {
245 continue;
246 }
247
248 field_into_tokens.push(quote! { #to_tokens::to_tokens(#ident, context, stream)? })
249 }
250
251 let ident = &variant.ident;
252
253 Ok(quote! {
254 Self::#ident(#(#idents,)*) => { #(#field_into_tokens;)* }
255 })
256 }
257
258 fn expand_variant_unit(&mut self, variant: &syn::Variant) -> TokenStream {
260 let ident = &variant.ident;
261
262 quote_spanned! { variant.span() =>
263 Self::#ident => ()
264 }
265 }
266}