1use proc_macro2::{Ident, Span, TokenStream};
2use quote::quote_spanned;
3use syn::{parse::Error, spanned::Spanned};
4
5use crate::mutator::Mutator;
6use crate::util::{expr_to_lit_string, ident_to_type, path_to_single_string, strip_raw_ident_prefix, ApplyMeta, AttrArg};
7
8#[derive(Debug)]
9pub struct FieldInfo<'a> {
10 pub ordinal: usize,
11 pub name: &'a syn::Ident,
12 pub generic_ident: syn::Ident,
13 pub ty: &'a syn::Type,
14 pub builder_attr: FieldBuilderAttr<'a>,
15}
16
17impl<'a> FieldInfo<'a> {
18 pub fn new(ordinal: usize, field: &'a syn::Field, field_defaults: FieldBuilderAttr<'a>) -> Result<FieldInfo<'a>, Error> {
19 if let Some(ref name) = field.ident {
20 FieldInfo {
21 ordinal,
22 name,
23 generic_ident: syn::Ident::new(&format!("__{}", strip_raw_ident_prefix(name.to_string())), Span::call_site()),
24 ty: &field.ty,
25 builder_attr: field_defaults.with(name, &field.attrs)?,
26 }
27 .post_process()
28 } else {
29 Err(Error::new(field.span(), "Nameless field in struct"))
30 }
31 }
32
33 pub fn generic_ty_param(&self) -> syn::GenericParam {
34 syn::GenericParam::Type(self.generic_ident.clone().into())
35 }
36
37 pub fn type_ident(&self) -> syn::Type {
38 ident_to_type(self.generic_ident.clone())
39 }
40
41 pub fn tuplized_type_ty_param(&self) -> syn::Type {
42 let mut types = syn::punctuated::Punctuated::default();
43 types.push(self.ty.clone());
44 types.push_punct(Default::default());
45 syn::TypeTuple {
46 paren_token: Default::default(),
47 elems: types,
48 }
49 .into()
50 }
51
52 pub fn type_from_inside_option(&self) -> Option<&syn::Type> {
53 let path = if let syn::Type::Path(type_path) = self.ty {
54 if type_path.qself.is_some() {
55 return None;
56 }
57 &type_path.path
58 } else {
59 return None;
60 };
61 let segment = path.segments.last()?;
62 if segment.ident != "Option" {
63 return None;
64 }
65 let generic_params = if let syn::PathArguments::AngleBracketed(generic_params) = &segment.arguments {
66 generic_params
67 } else {
68 return None;
69 };
70 if let syn::GenericArgument::Type(ty) = generic_params.args.first()? {
71 Some(ty)
72 } else {
73 None
74 }
75 }
76
77 pub fn setter_method_name(&self) -> Ident {
78 let name = strip_raw_ident_prefix(self.name.to_string());
79
80 if let (Some(prefix), Some(suffix)) = (&self.builder_attr.setter.prefix, &self.builder_attr.setter.suffix) {
81 Ident::new(&format!("{}{}{}", prefix, name, suffix), Span::call_site())
82 } else if let Some(prefix) = &self.builder_attr.setter.prefix {
83 Ident::new(&format!("{}{}", prefix, name), Span::call_site())
84 } else if let Some(suffix) = &self.builder_attr.setter.suffix {
85 Ident::new(&format!("{}{}", name, suffix), Span::call_site())
86 } else {
87 self.name.clone()
88 }
89 }
90
91 fn post_process(mut self) -> Result<Self, Error> {
92 if let Some(ref strip_bool) = self.builder_attr.setter.strip_bool {
93 if let Some(default_span) = self.builder_attr.default.as_ref().map(Spanned::span) {
94 let mut error = Error::new(
95 strip_bool.span,
96 "cannot set both strip_bool and default - default is assumed to be false",
97 );
98 error.combine(Error::new(default_span, "default set here"));
99 return Err(error);
100 }
101 self.builder_attr.default = Some(syn::Expr::Lit(syn::ExprLit {
102 attrs: Default::default(),
103 lit: syn::Lit::Bool(syn::LitBool {
104 value: false,
105 span: strip_bool.span,
106 }),
107 }));
108 }
109 Ok(self)
110 }
111}
112
113#[derive(Debug, Default, Clone)]
114pub struct FieldBuilderAttr<'a> {
115 pub default: Option<syn::Expr>,
116 pub via_mutators: Option<ViaMutators>,
117 pub deprecated: Option<&'a syn::Attribute>,
118 pub doc_comments: Vec<&'a syn::Expr>,
119 pub setter: SetterSettings,
120 pub mutators: Vec<Mutator>,
122 pub mutable_during_default_resolution: Option<Span>,
123}
124
125#[derive(Debug, Default, Clone)]
126pub struct SetterSettings {
127 pub doc: Option<syn::Expr>,
128 pub skip: Option<Span>,
129 pub auto_into: Option<Span>,
130 pub strip_option: Option<Strip>,
131 pub strip_bool: Option<Strip>,
132 pub transform: Option<Transform>,
133 pub prefix: Option<String>,
134 pub suffix: Option<String>,
135}
136
137impl<'a> FieldBuilderAttr<'a> {
138 pub fn with(mut self, name: &Ident, attrs: &'a [syn::Attribute]) -> Result<Self, Error> {
139 for attr in attrs {
140 let list = match &attr.meta {
141 syn::Meta::List(list) => {
142 let Some(path) = path_to_single_string(&list.path) else {
143 continue;
144 };
145
146 if path == "deprecated" {
147 self.deprecated = Some(attr);
148 continue;
149 }
150
151 if path != "builder" {
152 continue;
153 }
154
155 list
156 }
157 syn::Meta::NameValue(syn::MetaNameValue { path, value, .. }) => {
158 match path_to_single_string(path).as_deref() {
159 Some("deprecated") => self.deprecated = Some(attr),
160 Some("doc") => self.doc_comments.push(value),
161 _ => continue,
162 }
163
164 continue;
165 }
166 syn::Meta::Path(path) => {
167 match path_to_single_string(path).as_deref() {
168 Some("deprecated") => self.deprecated = Some(attr),
169 _ => continue,
170 }
171
172 continue;
173 }
174 };
175
176 self.apply_subsections(list)?;
177 }
178
179 for mutator in self.mutators.iter_mut() {
180 mutator.required_fields.insert(name.clone());
181 }
182
183 self.inter_fields_conflicts()?;
184
185 Ok(self)
186 }
187
188 fn inter_fields_conflicts(&self) -> Result<(), Error> {
189 if let (Some(skip), None) = (&self.setter.skip, &self.default) {
190 return Err(Error::new(
191 *skip,
192 "#[builder(skip)] must be accompanied by default or default_code",
193 ));
194 }
195
196 let conflicting_transformations = [
197 ("transform", self.setter.transform.as_ref().map(|t| &t.span)),
198 ("strip_option", self.setter.strip_option.as_ref().map(|s| &s.span)),
199 ("strip_bool", self.setter.strip_bool.as_ref().map(|s| &s.span)),
200 ];
201 let mut conflicting_transformations = conflicting_transformations
202 .iter()
203 .filter_map(|(caption, span)| span.map(|span| (caption, span)))
204 .collect::<Vec<_>>();
205
206 if 1 < conflicting_transformations.len() {
207 let (first_caption, first_span) = conflicting_transformations.pop().unwrap();
208 let conflicting_captions = conflicting_transformations
209 .iter()
210 .map(|(caption, _)| **caption)
211 .collect::<Vec<_>>();
212 let mut error = Error::new(
213 *first_span,
214 format_args!("{} conflicts with {}", first_caption, conflicting_captions.join(", ")),
215 );
216 for (caption, span) in conflicting_transformations {
217 error.combine(Error::new(*span, format_args!("{} set here", caption)));
218 }
219 return Err(error);
220 }
221 Ok(())
222 }
223}
224
225impl ApplyMeta for FieldBuilderAttr<'_> {
226 fn apply_meta(&mut self, expr: AttrArg) -> Result<(), Error> {
227 match expr.name().to_string().as_str() {
228 "default" => match expr {
229 AttrArg::Flag(ident) => {
230 self.default =
231 Some(syn::parse2(quote_spanned!(ident.span() => ::core::default::Default::default())).unwrap());
232 Ok(())
233 }
234 AttrArg::KeyValue(key_value) => {
235 self.default = Some(key_value.parse_value()?);
236 Ok(())
237 }
238 AttrArg::Not { .. } => {
239 self.default = None;
240 Ok(())
241 }
242 AttrArg::Sub(_) => Err(expr.incorrect_type()),
243 },
244 "default_code" => {
245 use std::str::FromStr;
246
247 let code = expr.key_value()?.parse_value::<syn::LitStr>()?;
248 let tokenized_code = TokenStream::from_str(&code.value())?;
249 self.default = Some(syn::parse2(tokenized_code).map_err(|e| Error::new_spanned(code, format!("{}", e)))?);
250
251 Ok(())
252 }
253 "setter" => self.setter.apply_sub_attr(expr.sub_attr()?),
254 "mutable_during_default_resolution" => expr.apply_flag_to_field(
255 &mut self.mutable_during_default_resolution,
256 "made mutable during default resolution",
257 ),
258 "via_mutators" => {
259 match expr {
260 AttrArg::Flag(ident) => {
261 self.via_mutators = Some(ViaMutators {
262 span: ident.span(),
263 init: syn::parse2(quote_spanned!(ident.span() => ::core::default::Default::default())).unwrap(),
264 });
265 }
266 AttrArg::KeyValue(key_value) => {
267 self.via_mutators = Some(ViaMutators {
268 span: key_value.span(),
269 init: key_value.parse_value()?,
270 });
271 }
272 AttrArg::Not { .. } => {
273 self.via_mutators = None;
274 }
275 AttrArg::Sub(sub) => {
276 if let Some(via_mutators) = self.via_mutators.as_mut() {
277 if let Some(joined_span) = via_mutators.span.join(sub.span()) {
278 via_mutators.span = joined_span;
279 } else {
280 via_mutators.span = sub.span();
282 };
283 via_mutators.apply_sub_attr(sub)?;
284 } else {
285 let mut via_mutators = ViaMutators::empty_spanned(sub.span());
286 via_mutators.apply_sub_attr(sub)?;
287 self.via_mutators = Some(via_mutators);
288 }
289 }
290 }
291 Ok(())
292 }
293 "mutators" => {
294 self.mutators.extend(expr.sub_attr()?.undelimited()?);
295 Ok(())
296 }
297 _ => Err(Error::new_spanned(
298 expr.name(),
299 format!("Unknown parameter {:?}", expr.name().to_string()),
300 )),
301 }
302 }
303}
304
305impl ApplyMeta for SetterSettings {
306 fn apply_meta(&mut self, expr: AttrArg) -> Result<(), Error> {
307 match expr.name().to_string().as_str() {
308 "doc" => {
309 self.doc = expr.key_value_or_not()?.map(|kv| kv.parse_value()).transpose()?;
310 Ok(())
311 }
312 "transform" => {
313 self.transform = if let Some(key_value) = expr.key_value_or_not()? {
314 Some(parse_transform_closure(key_value.name.span(), key_value.parse_value()?)?)
315 } else {
316 None
317 };
318 Ok(())
319 }
320 "prefix" => {
321 self.prefix = if let Some(key_value) = expr.key_value_or_not()? {
322 Some(expr_to_lit_string(&key_value.parse_value()?)?)
323 } else {
324 None
325 };
326 Ok(())
327 }
328 "suffix" => {
329 self.suffix = if let Some(key_value) = expr.key_value_or_not()? {
330 Some(expr_to_lit_string(&key_value.parse_value()?)?)
331 } else {
332 None
333 };
334 Ok(())
335 }
336 "skip" => expr.apply_flag_to_field(&mut self.skip, "skipped"),
337 "into" => expr.apply_flag_to_field(&mut self.auto_into, "calling into() on the argument"),
338 "strip_option" => {
339 expr.apply_potentialy_empty_sub_to_field(&mut self.strip_option, "putting the argument in Some(...)", Strip::new)
340 }
341 "strip_bool" => expr.apply_potentialy_empty_sub_to_field(
342 &mut self.strip_bool,
343 "zero arguments setter, sets the field to true",
344 Strip::new,
345 ),
346 _ => Err(Error::new_spanned(
347 expr.name(),
348 format!("Unknown parameter {:?}", expr.name().to_string()),
349 )),
350 }
351 }
352}
353
354#[derive(Debug, Clone)]
355pub struct Strip {
356 pub fallback: Option<syn::Ident>,
357 pub fallback_prefix: Option<String>,
358 pub fallback_suffix: Option<String>,
359 pub ignore_invalid: bool,
360 span: Span,
361}
362
363impl Strip {
364 fn new(span: Span) -> Self {
365 Self {
366 fallback: None,
367 fallback_prefix: None,
368 fallback_suffix: None,
369 ignore_invalid: false,
370 span,
371 }
372 }
373}
374
375impl ApplyMeta for Strip {
376 fn apply_meta(&mut self, expr: AttrArg) -> Result<(), Error> {
377 match expr.name().to_string().as_str() {
378 "fallback" => {
379 if self.fallback.is_some() {
380 return Err(Error::new_spanned(
381 expr.name(),
382 format!("Duplicate fallback parameter {:?}", expr.name().to_string()),
383 ));
384 }
385
386 let ident: syn::Ident = expr.key_value().map(|kv| kv.parse_value())??;
387 self.fallback = Some(ident);
388 Ok(())
389 }
390 "fallback_prefix" => {
391 if self.fallback_prefix.is_some() {
392 return Err(Error::new_spanned(
393 expr.name(),
394 format!("Duplicate fallback_prefix parameter {:?}", expr.name().to_string()),
395 ));
396 }
397
398 self.fallback_prefix = Some(expr.key_value()?.parse_value::<syn::LitStr>()?.value());
399 Ok(())
400 }
401 "fallback_suffix" => {
402 if self.fallback_suffix.is_some() {
403 return Err(Error::new_spanned(
404 expr.name(),
405 format!("Duplicate fallback_suffix parameter {:?}", expr.name().to_string()),
406 ));
407 }
408
409 self.fallback_suffix = Some(expr.key_value()?.parse_value::<syn::LitStr>()?.value());
410 Ok(())
411 }
412 "ignore_invalid" => {
413 if self.ignore_invalid {
414 return Err(Error::new_spanned(
415 expr.name(),
416 format!("Duplicate ignore_invalid parameter {:?}", expr.name().to_string()),
417 ));
418 }
419
420 expr.flag()?;
421 self.ignore_invalid = true;
422 Ok(())
423 }
424 _ => Err(Error::new_spanned(
425 expr.name(),
426 format!("Unknown parameter {:?}", expr.name().to_string()),
427 )),
428 }
429 }
430}
431
432#[derive(Debug, Clone)]
433pub struct Transform {
434 pub params: Vec<(syn::Pat, syn::Type)>,
435 pub body: syn::Expr,
436 span: Span,
437}
438
439fn parse_transform_closure(span: Span, expr: syn::Expr) -> Result<Transform, Error> {
440 let closure = match expr {
441 syn::Expr::Closure(closure) => closure,
442 _ => return Err(Error::new_spanned(expr, "Expected closure")),
443 };
444 if let Some(kw) = &closure.asyncness {
445 return Err(Error::new(kw.span, "Transform closure cannot be async"));
446 }
447 if let Some(kw) = &closure.capture {
448 return Err(Error::new(kw.span, "Transform closure cannot be move"));
449 }
450
451 let params = closure
452 .inputs
453 .into_iter()
454 .map(|input| match input {
455 syn::Pat::Type(pat_type) => Ok((*pat_type.pat, *pat_type.ty)),
456 _ => Err(Error::new_spanned(input, "Transform closure must explicitly declare types")),
457 })
458 .collect::<Result<Vec<_>, _>>()?;
459
460 Ok(Transform {
461 params,
462 body: *closure.body,
463 span,
464 })
465}
466
467#[derive(Debug, Clone)]
468pub struct ViaMutators {
469 pub span: Span,
470 pub init: syn::Expr,
471}
472
473impl ViaMutators {
474 fn empty_spanned(span: Span) -> Self {
475 Self {
476 span,
477 init: syn::parse2(quote_spanned!(span => ::core::default::Default::default())).unwrap(),
478 }
479 }
480}
481
482impl ApplyMeta for ViaMutators {
483 fn apply_meta(&mut self, expr: AttrArg) -> Result<(), Error> {
484 match expr.name().to_string().as_str() {
485 "init" => {
486 self.init = expr.key_value()?.parse_value()?;
487 Ok(())
488 }
489 _ => Err(Error::new_spanned(
490 expr.name(),
491 format!("Unknown parameter {:?}", expr.name().to_string()),
492 )),
493 }
494 }
495}