educe/trait_handlers/default/
default_struct.rs1use std::{fmt::Write, str::FromStr};
2
3use proc_macro2::TokenStream;
4use quote::{quote, ToTokens};
5use syn::{Data, DeriveInput, Fields, Generics, Lit, Meta};
6
7use super::{
8 super::TraitHandler,
9 models::{FieldAttributeBuilder, TypeAttributeBuilder},
10};
11use crate::Trait;
12
13pub struct DefaultStructHandler;
14
15impl TraitHandler for DefaultStructHandler {
16 fn trait_meta_handler(
17 ast: &DeriveInput,
18 tokens: &mut TokenStream,
19 traits: &[Trait],
20 meta: &Meta,
21 ) {
22 let type_attribute = TypeAttributeBuilder {
23 enable_flag: true,
24 enable_new: true,
25 enable_expression: true,
26 enable_bound: true,
27 }
28 .from_default_meta(meta);
29
30 let bound = type_attribute
31 .bound
32 .into_punctuated_where_predicates_by_generic_parameters(&ast.generics.params);
33
34 let mut builder_tokens = TokenStream::new();
35
36 if let Data::Struct(data) = &ast.data {
37 match type_attribute.expression {
38 Some(expression) => {
39 for field in data.fields.iter() {
40 let _ = FieldAttributeBuilder {
41 enable_flag: false,
42 enable_literal: false,
43 enable_expression: false,
44 }
45 .from_attributes(&field.attrs, traits);
46 }
47
48 builder_tokens.extend(quote!(#expression));
49 },
50 None => match &data.fields {
51 Fields::Unit => {
52 let ident = &ast.ident;
53
54 builder_tokens.extend(quote!(#ident));
55 },
56 Fields::Unnamed(_) => {
57 let mut struct_tokens = ast.ident.to_string();
58
59 struct_tokens.push('(');
60
61 for field in data.fields.iter() {
62 let field_attribute = FieldAttributeBuilder {
63 enable_flag: false,
64 enable_literal: true,
65 enable_expression: true,
66 }
67 .from_attributes(&field.attrs, traits);
68
69 match field_attribute.literal {
70 Some(value) => match &value {
71 Lit::Str(s) => {
72 struct_tokens
73 .write_fmt(format_args!(
74 "core::convert::Into::into({s})",
75 s = s.into_token_stream()
76 ))
77 .unwrap();
78 },
79 _ => {
80 struct_tokens
81 .push_str(&value.into_token_stream().to_string());
82 },
83 },
84 None => match field_attribute.expression {
85 Some(expression) => {
86 struct_tokens.push_str(&expression);
87 },
88 None => {
89 let typ = field.ty.clone().into_token_stream().to_string();
90
91 struct_tokens
92 .write_fmt(format_args!(
93 "<{typ} as core::default::Default>::default()",
94 typ = typ
95 ))
96 .unwrap();
97 },
98 },
99 }
100
101 struct_tokens.push(',');
102 }
103
104 struct_tokens.push(')');
105
106 builder_tokens.extend(TokenStream::from_str(&struct_tokens).unwrap());
107 },
108 Fields::Named(_) => {
109 let mut struct_tokens = ast.ident.to_string();
110
111 struct_tokens.push('{');
112
113 for field in data.fields.iter() {
114 let field_attribute = FieldAttributeBuilder {
115 enable_flag: false,
116 enable_literal: true,
117 enable_expression: true,
118 }
119 .from_attributes(&field.attrs, traits);
120
121 let field_name = field.ident.as_ref().unwrap().to_string();
122
123 struct_tokens
124 .write_fmt(format_args!("{field_name}: ", field_name = field_name))
125 .unwrap();
126
127 match field_attribute.literal {
128 Some(value) => match &value {
129 Lit::Str(s) => {
130 struct_tokens
131 .write_fmt(format_args!(
132 "core::convert::Into::into({s})",
133 s = s.into_token_stream()
134 ))
135 .unwrap();
136 },
137 _ => {
138 struct_tokens
139 .push_str(&value.into_token_stream().to_string());
140 },
141 },
142 None => match field_attribute.expression {
143 Some(expression) => {
144 struct_tokens.push_str(&expression);
145 },
146 None => {
147 let typ = field.ty.clone().into_token_stream().to_string();
148
149 struct_tokens
150 .write_fmt(format_args!(
151 "<{typ} as core::default::Default>::default()",
152 typ = typ
153 ))
154 .unwrap();
155 },
156 },
157 }
158
159 struct_tokens.push(',');
160 }
161
162 struct_tokens.push('}');
163
164 builder_tokens.extend(TokenStream::from_str(&struct_tokens).unwrap());
165 },
166 },
167 }
168 }
169
170 let ident = &ast.ident;
171
172 let mut generics_cloned: Generics = ast.generics.clone();
173
174 let where_clause = generics_cloned.make_where_clause();
175
176 for where_predicate in bound {
177 where_clause.predicates.push(where_predicate);
178 }
179
180 let (impl_generics, ty_generics, where_clause) = generics_cloned.split_for_impl();
181
182 let default_impl = quote! {
183 impl #impl_generics core::default::Default for #ident #ty_generics #where_clause {
184 #[inline]
185 fn default() -> Self {
186 #builder_tokens
187 }
188 }
189 };
190
191 tokens.extend(default_impl);
192
193 if type_attribute.new {
194 let new_impl = quote! {
195 impl #impl_generics #ident #ty_generics #where_clause {
196 #[inline]
198 pub fn new() -> Self {
199 <Self as core::default::Default>::default()
200 }
201 }
202 };
203
204 tokens.extend(new_impl);
205 }
206 }
207}