1use alloc::{format, vec::Vec};
4
5use proc_macro2::TokenStream;
6
7use quote::{ToTokens, quote};
8
9use syn::Ident;
10
11use super::{
12 Target,
13 common::{FieldRef, Format, ImportRoot, InlineOptions, Transparent},
14 enumerate::{Enumeration, Variant},
15 structure::{Structure, StructureOptions},
16};
17
18pub struct Expand {}
20
21impl Expand {
22 #[inline]
24 pub fn target(target_value: Target) -> syn::Result<TokenStream> {
25 match target_value {
26 Target::Struct(structure) => Self::structure(structure),
27 Target::Enum(enumeration) => Self::enumeration(enumeration),
28 }
29 }
30}
31
32impl Expand {
33 pub fn structure(target_value: Structure) -> syn::Result<TokenStream> {
35 let Structure {
36 inline_opts,
37 root_import,
38 name_ident,
39 generics,
40 options,
41 field_list,
42 } = target_value;
43
44 let inline_expand = match inline_opts {
45 Some(InlineOptions::Neutral) => quote! { #[inline] },
46 Some(InlineOptions::Always) => quote! { #[inline(always)] },
47 Some(InlineOptions::Never) => quote! { #[inline(never)] },
48 None => quote! {},
49 };
50
51 let root_expand = root_import.map_or_else(|| quote! { ::core }, |ImportRoot(root)| root.to_token_stream());
52
53 let (impl_generics, ty_generics, where_clause) = generics.split_for_impl();
54
55 let field_pat = field_list.pattern()?;
56
57 match options {
58 StructureOptions::Standalone {
59 source_field,
60 format_args: Format { format, format_args },
61 } => {
62 let source_expand = if let Some(field) = source_field {
63 quote! { Some(&self.#field) }
64 } else {
65 quote! { None }
66 };
67
68 Ok(quote! {
69 #[automatically_derived]
70 impl #impl_generics #root_expand::error::Error for #name_ident #ty_generics #where_clause {
71 #inline_expand
72 fn source(&self) -> Option<&(dyn #root_expand::error::Error + 'static)> {
73 #source_expand
74 }
75 }
76
77 #[automatically_derived]
78 impl #impl_generics #root_expand::fmt::Display for #name_ident #ty_generics #where_clause {
79 #inline_expand
80 fn fmt(&self, f: &mut #root_expand::fmt::Formatter<'_>) -> #root_expand::fmt::Result {
81 let &Self #field_pat = self;
82
83 #root_expand::write!(f, #format, #format_args)
84 }
85 }
86 })
87 }
88 StructureOptions::Transparent(Transparent(target_field)) => {
89 let field_expand = quote! {
90 self.#target_field
91 };
92
93 Ok(quote! {
94 #[automatically_derived]
95 impl #impl_generics #root_expand::error::Error for #name_ident #ty_generics #where_clause {
96 #inline_expand
97 fn source(&self) -> Option<&(dyn #root_expand::error::Error + 'static)> {
98 #root_expand::error::Error::source(&#field_expand)
99 }
100 }
101
102 #[automatically_derived]
103 impl #impl_generics #root_expand::fmt::Display for #name_ident #ty_generics #where_clause {
104 #inline_expand
105 fn fmt(&self, f: &mut #root_expand::fmt::Formatter<'_>) -> #root_expand::fmt::Result {
106 let &Self #field_pat = self;
107
108 #root_expand::fmt::Display::fmt(&#field_expand, f)
109 }
110 }
111 })
112 }
113 StructureOptions::Forward {
114 field_ref,
115 field_type,
116 source_field,
117 format_args: Format { format, format_args },
118 } => {
119 let source_expand = if let Some(field) = source_field {
120 quote! { Some(&self.#field) }
121 } else {
122 quote! { None }
123 };
124
125 let from_expand = match field_ref {
126 FieldRef::Named(ref field) => quote! {
127 #[automatically_derived]
128 impl #impl_generics From<#field_type> for #name_ident #ty_generics #where_clause {
129 #inline_expand
130 fn from(#field: #field_type) -> Self {
131 Self { #field }
132 }
133 }
134 },
135 FieldRef::Indexed(..) => quote! {
136 #[automatically_derived]
137 impl #impl_generics From<#field_type> for #name_ident #ty_generics #where_clause {
138 #inline_expand
139 fn from(field: #field_type) -> Self {
140 Self(field)
141 }
142 }
143 },
144 };
145
146 Ok(quote! {
147 #from_expand
148
149 #[automatically_derived]
150 impl #impl_generics #root_expand::error::Error for #name_ident #ty_generics #where_clause {
151 #inline_expand
152 fn source(&self) -> Option<&(dyn #root_expand::error::Error + 'static)> {
153 #source_expand
154 }
155 }
156
157 #[automatically_derived]
158 impl #impl_generics #root_expand::fmt::Display for #name_ident #ty_generics #where_clause {
159 #inline_expand
160 fn fmt(&self, f: &mut #root_expand::fmt::Formatter<'_>) -> #root_expand::fmt::Result {
161 let &Self #field_pat = self;
162
163 #root_expand::write!(f, #format, #format_args)
164 }
165 }
166 })
167 }
168 }
169 }
170
171 pub fn enumeration(target_value: Enumeration) -> syn::Result<TokenStream> {
173 let Enumeration {
174 inline_opts,
175 root_import,
176 name_ident,
177 generics,
178 variant_list,
179 } = target_value;
180
181 let inline_expand = match inline_opts {
182 Some(InlineOptions::Neutral) => quote! { #[inline] },
183 Some(InlineOptions::Always) => quote! { #[inline(always)] },
184 Some(InlineOptions::Never) => quote! { #[inline(never)] },
185 None => quote! {},
186 };
187
188 let root_expand = root_import.map_or_else(|| quote! { ::core }, |ImportRoot(root)| root.to_token_stream());
189
190 let (impl_generics, ty_generics, where_clause) = generics.split_for_impl();
191
192 let mut source_expand = Vec::new();
193
194 let mut from_expand = Vec::new();
195
196 let mut display_expand = Vec::new();
197
198 for variant in variant_list {
199 match variant {
200 Variant::Struct {
201 format: Format { format, format_args },
202 variant_name,
203 field_list,
204 source_field,
205 } => {
206 let field_pat = field_list.pattern()?;
207
208 if let Some(source_field) = source_field {
209 let field_expand = match source_field {
210 FieldRef::Named(ref field) => quote! { self.#field },
211 FieldRef::Indexed(index) => Ident::new(&format!("_{index}"), variant_name.span()).into_token_stream(),
212 };
213
214 source_expand.push(quote! {
215 &Self::#variant_name #field_pat => Some(#field_expand),
216 });
217 } else {
218 source_expand.push(quote! {
219 &Self::#variant_name #field_pat => None,
220 });
221 }
222
223 display_expand.push(quote! {
224 &Self::#variant_name #field_pat => #root_expand::write!(f, #format, #format_args),
225 });
226 }
227 Variant::Unit {
228 format: Format { format, format_args },
229 variant_name,
230 } => {
231 source_expand.push(quote! {
232 &Self::#variant_name => None,
233 });
234
235 display_expand.push(quote! {
236 &Self::#variant_name => #root_expand::write!(f, #format, #format_args),
237 });
238 }
239 Variant::Transparent {
240 transparent: Transparent(trans_field),
241 variant_name,
242 field_list,
243 } => {
244 let trans_expand = match trans_field {
245 FieldRef::Named(ref field) => quote! { #field },
246 FieldRef::Indexed(index) => Ident::new(&format!("_{index}"), variant_name.span()).into_token_stream(),
247 };
248
249 let field_pat = field_list.pattern()?;
250
251 source_expand.push(quote! {
252 &Self::#variant_name #field_pat => #root_expand::error::Error::source(#trans_expand),
253 });
254
255 display_expand.push(quote! {
256 &Self::#variant_name #field_pat => #root_expand::fmt::Display::fmt(#trans_expand, f),
257 });
258 }
259 Variant::Forward {
260 format: Format { format, format_args },
261 variant_name,
262 field_ref,
263 field_type,
264 } => {
265 let bare_field_name = quote!(#field_ref);
266
267 source_expand.push(quote! {
268 &Self::#variant_name { #bare_field_name: ref target_field } => #root_expand::error::Error::source(target_field),
269 });
270
271 from_expand.push(match field_ref {
272 FieldRef::Named(ref field) => quote! {
273 #[automatically_derived]
274 impl #impl_generics From<#field_type> for #name_ident #ty_generics #where_clause {
275 #inline_expand
276 fn from(#field: #field_type) -> Self {
277 Self::#variant_name { #field }
278 }
279 }
280 },
281 FieldRef::Indexed(..) => quote! {
282 #[automatically_derived]
283 impl #impl_generics From<#field_type> for #name_ident #ty_generics #where_clause {
284 #inline_expand
285 fn from(field: #field_type) -> Self {
286 Self::#variant_name(field)
287 }
288 }
289 },
290 });
291
292 let replaced_field_name = match field_ref {
293 FieldRef::Named(..) => None,
294 FieldRef::Indexed(ref field) => Some({
295 let ident = Ident::new(&format!("_{field}"), variant_name.span());
296
297 quote! {
298 : ref #ident
299 }
300 }),
301 };
302
303 display_expand.push(quote! {
304 &Self::#variant_name { #bare_field_name #replaced_field_name } => #root_expand::write!(f, #format, #format_args),
305 });
306 }
307 }
308 }
309
310 Ok(quote! {
311 #(#from_expand)*
312
313 #[automatically_derived]
314 impl #impl_generics #root_expand::error::Error for #name_ident #ty_generics #where_clause {
315 #inline_expand
316 fn source(&self) -> Option<&(dyn #root_expand::error::Error + 'static)> {
317 match self {
318 #(#source_expand)*
319 }
320 }
321 }
322
323 #[automatically_derived]
324 impl #impl_generics #root_expand::fmt::Display for #name_ident #ty_generics #where_clause {
325 #inline_expand
326 fn fmt(&self, f: &mut #root_expand::fmt::Formatter<'_>) -> #root_expand::fmt::Result {
327 match self {
328 #(#display_expand)*
329 }
330 }
331 }
332 })
333 }
334}