derive_builder_core_fork_arti/
setter.rs1#![allow(clippy::useless_let_if_seq)]
2use std::borrow::Cow;
3
4use proc_macro2::{Span, TokenStream};
5use quote::{ToTokens, TokenStreamExt};
6use syn;
7
8use BuilderFieldType;
9use BuilderPattern;
10use DeprecationNotes;
11use Each;
12
13#[derive(Debug, Clone)]
43pub struct Setter<'a> {
44 pub setter_enabled: bool,
46 pub try_setter: bool,
48 pub visibility: Cow<'a, syn::Visibility>,
50 pub pattern: BuilderPattern,
52 pub attrs: &'a [syn::Attribute],
54 pub ident: syn::Ident,
56 pub field_ident: &'a syn::Ident,
58 pub field_type: BuilderFieldType<'a>,
62 pub generic_into: bool,
64 pub strip_option: bool,
67 pub deprecation_notes: &'a DeprecationNotes,
69 pub each: Option<&'a Each>,
71 pub sub_accessor: bool,
73}
74
75impl<'a> ToTokens for Setter<'a> {
76 fn to_tokens(&self, tokens: &mut TokenStream) {
77 if self.setter_enabled {
78 let pattern = self.pattern;
79 let vis = &self.visibility;
80 let field_ident = self.field_ident;
81 let ident = &self.ident;
82 let attrs = self.attrs;
83 let deprecation_notes = self.deprecation_notes;
84
85 let self_param: TokenStream;
86 let return_ty: TokenStream;
87 let self_into_return_ty: TokenStream;
88
89 match pattern {
90 BuilderPattern::Owned => {
91 self_param = quote!(self);
92 return_ty = quote!(Self);
93 self_into_return_ty = quote!(self);
94 }
95 BuilderPattern::Mutable => {
96 self_param = quote!(&mut self);
97 return_ty = quote!(&mut Self);
98 self_into_return_ty = quote!(self);
99 }
100 BuilderPattern::Immutable => {
101 self_param = quote!(&self);
102 return_ty = quote!(Self);
103 self_into_return_ty =
104 quote!(::derive_builder::export::core::clone::Clone::clone(self));
105 }
106 };
107
108 let ty_params: TokenStream;
109 let param_ty: TokenStream;
110 let mut into_value: TokenStream;
111
112 let (field_type, builder_field_is_option) = self.field_type.setter_type_info();
113
114 let (ty, stripped_option) = {
115 if self.strip_option {
116 match extract_type_from_option(field_type) {
117 Some(ty) => (ty, true),
118 None => (field_type, false),
119 }
120 } else {
121 (field_type, false)
122 }
123 };
124
125 if self.generic_into {
126 ty_params = quote!(<VALUE: ::derive_builder::export::core::convert::Into<#ty>>);
127 param_ty = quote!(VALUE);
128 into_value = quote!(value.into());
129 } else {
130 ty_params = quote!();
131 param_ty = quote!(#ty);
132 into_value = quote!(value);
133 }
134 if stripped_option {
137 into_value = wrap_expression_in_some(into_value);
138 }
139 if builder_field_is_option {
140 into_value = wrap_expression_in_some(into_value);
141 }
142
143 if self.sub_accessor {
144 tokens.append_all(quote!(
147 #(#attrs)*
148 #vis fn #ident #ty_params (&mut self)
149 -> &mut #param_ty
150 {
151 &mut self.#field_ident
152 }
153 ));
154 } else {
155 tokens.append_all(quote!(
156 #(#attrs)*
157 #[allow(unused_mut)]
158 #vis fn #ident #ty_params (#self_param, value: #param_ty)
159 -> #return_ty
160 {
161 #deprecation_notes
162 let mut new = #self_into_return_ty;
163 new.#field_ident = #into_value;
164 new
165 }
166 ));
167 }
168
169 if self.try_setter {
170 let try_ty_params =
171 quote!(<VALUE: ::derive_builder::export::core::convert::TryInto<#ty>>);
172 let try_ident = syn::Ident::new(&format!("try_{}", ident), Span::call_site());
173
174 let mut converted = quote! {converted};
175 if builder_field_is_option {
176 converted = wrap_expression_in_some(converted);
177 }
178
179 tokens.append_all(quote!(
180 #(#attrs)*
181 #vis fn #try_ident #try_ty_params (#self_param, value: VALUE)
182 -> ::derive_builder::export::core::result::Result<#return_ty, VALUE::Error>
183 {
184 let converted : #ty = value.try_into()?;
185 let mut new = #self_into_return_ty;
186 new.#field_ident = #converted;
187 Ok(new)
188 }
189 ));
190 }
191
192 if let Some(each) = self.each {
193 let ident_each = &each.name;
194
195 let get_initialized_collection = if stripped_option {
197 quote!(get_or_insert_with(|| Some(
199 ::derive_builder::export::core::default::Default::default()
200 ))
201 .get_or_insert_with(::derive_builder::export::core::default::Default::default))
202 } else {
203 quote!(get_or_insert_with(
205 ::derive_builder::export::core::default::Default::default
206 ))
207 };
208
209 let ty_params: TokenStream;
210 let param_ty: TokenStream;
211 let into_item: TokenStream;
212
213 if each.into {
214 ty_params = quote!(<VALUE, FROM_VALUE: ::derive_builder::export::core::convert::Into<VALUE>>);
215 param_ty = quote!(FROM_VALUE);
216 into_item = quote!(::derive_builder::export::core::convert::Into::into(item));
217 } else {
218 ty_params = quote!(<VALUE>);
219 param_ty = quote!(VALUE);
220 into_item = quote!(item);
221 }
222
223 tokens.append_all(quote!(
224 #(#attrs)*
225 #[allow(unused_mut)]
226 #vis fn #ident_each #ty_params(#self_param, item: #param_ty) -> #return_ty
227 where
228 #ty: ::derive_builder::export::core::default::Default + ::derive_builder::export::core::iter::Extend<VALUE>,
229 {
230 #deprecation_notes
231 let mut new = #self_into_return_ty;
232 new.#field_ident
233 .#get_initialized_collection
234 .extend(::derive_builder::export::core::option::Option::Some(#into_item));
235 new
236 }
237 ));
238 }
239 }
240 }
241}
242
243fn wrap_expression_in_some(bare_value: impl ToTokens) -> TokenStream {
245 quote!( ::derive_builder::export::core::option::Option::Some(#bare_value) )
246}
247
248fn extract_type_from_option(ty: &syn::Type) -> Option<&syn::Type> {
254 use syn::punctuated::Pair;
255 use syn::token::Colon2;
256 use syn::{GenericArgument, Path, PathArguments, PathSegment};
257
258 fn extract_type_path(ty: &syn::Type) -> Option<&Path> {
259 match *ty {
260 syn::Type::Path(ref typepath) if typepath.qself.is_none() => Some(&typepath.path),
261 _ => None,
262 }
263 }
264
265 fn extract_option_segment(path: &Path) -> Option<Pair<&PathSegment, &Colon2>> {
268 let idents_of_path = path.segments.iter().fold(String::new(), |mut acc, v| {
269 acc.push_str(&v.ident.to_string());
270 acc.push('|');
271 acc
272 });
273 vec!["Option|", "std|option|Option|", "core|option|Option|"]
274 .into_iter()
275 .find(|s| idents_of_path == *s)
276 .and_then(|_| path.segments.last().map(Pair::End))
277 }
278
279 extract_type_path(ty)
280 .and_then(extract_option_segment)
281 .and_then(|pair_path_segment| {
282 let type_params = &pair_path_segment.into_value().arguments;
283 match *type_params {
285 PathArguments::AngleBracketed(ref params) => params.args.first(),
286 _ => None,
287 }
288 })
289 .and_then(|generic_arg| match *generic_arg {
290 GenericArgument::Type(ref ty) => Some(ty),
291 _ => None,
292 })
293}
294
295#[doc(hidden)]
298#[macro_export]
299macro_rules! default_setter {
300 () => {
301 Setter {
302 setter_enabled: true,
303 try_setter: false,
304 visibility: ::std::borrow::Cow::Owned(parse_quote!(pub)),
305 pattern: BuilderPattern::Mutable,
306 attrs: &vec![],
307 ident: syn::Ident::new("foo", ::proc_macro2::Span::call_site()),
308 field_ident: &syn::Ident::new("foo", ::proc_macro2::Span::call_site()),
309 field_type: BuilderFieldType::Optional(Box::leak(Box::new(parse_quote!(Foo)))),
310 generic_into: false,
311 strip_option: false,
312 deprecation_notes: &Default::default(),
313 each: None,
314 sub_accessor: false,
315 }
316 };
317}
318
319#[cfg(test)]
320mod tests {
321 #[allow(unused_imports)]
322 use super::*;
323
324 #[test]
325 fn immutable() {
326 let mut setter = default_setter!();
327 setter.pattern = BuilderPattern::Immutable;
328
329 assert_eq!(
330 quote!(#setter).to_string(),
331 quote!(
332 #[allow(unused_mut)]
333 pub fn foo(&self, value: Foo) -> Self {
334 let mut new = ::derive_builder::export::core::clone::Clone::clone(self);
335 new.foo = ::derive_builder::export::core::option::Option::Some(value);
336 new
337 }
338 )
339 .to_string()
340 );
341 }
342
343 #[test]
344 fn mutable() {
345 let mut setter = default_setter!();
346 setter.pattern = BuilderPattern::Mutable;
347
348 assert_eq!(
349 quote!(#setter).to_string(),
350 quote!(
351 #[allow(unused_mut)]
352 pub fn foo(&mut self, value: Foo) -> &mut Self {
353 let mut new = self;
354 new.foo = ::derive_builder::export::core::option::Option::Some(value);
355 new
356 }
357 )
358 .to_string()
359 );
360 }
361
362 #[test]
363 fn owned() {
364 let mut setter = default_setter!();
365 setter.pattern = BuilderPattern::Owned;
366
367 assert_eq!(
368 quote!(#setter).to_string(),
369 quote!(
370 #[allow(unused_mut)]
371 pub fn foo(self, value: Foo) -> Self {
372 let mut new = self;
373 new.foo = ::derive_builder::export::core::option::Option::Some(value);
374 new
375 }
376 )
377 .to_string()
378 );
379 }
380
381 #[test]
382 fn private() {
383 let vis = Cow::Owned(syn::Visibility::Inherited);
384
385 let mut setter = default_setter!();
386 setter.visibility = vis;
387
388 assert_eq!(
389 quote!(#setter).to_string(),
390 quote!(
391 #[allow(unused_mut)]
392 fn foo(&mut self, value: Foo) -> &mut Self {
393 let mut new = self;
394 new.foo = ::derive_builder::export::core::option::Option::Some(value);
395 new
396 }
397 )
398 .to_string()
399 );
400 }
401
402 #[test]
403 fn generic() {
404 let mut setter = default_setter!();
405 setter.generic_into = true;
406
407 #[rustfmt::skip]
408 assert_eq!(
409 quote!(#setter).to_string(),
410 quote!(
411 #[allow(unused_mut)]
412 pub fn foo<VALUE: ::derive_builder::export::core::convert::Into<Foo>>(
413 &mut self,
414 value: VALUE
415 ) -> &mut Self {
416 let mut new = self;
417 new.foo = ::derive_builder::export::core::option::Option::Some(value.into());
418 new
419 }
420 )
421 .to_string()
422 );
423 }
424
425 #[test]
426 fn strip_option() {
427 let ty = parse_quote!(Option<Foo>);
428 let mut setter = default_setter!();
429 setter.strip_option = true;
430 setter.field_type = BuilderFieldType::Optional(&ty);
431
432 #[rustfmt::skip]
433 assert_eq!(
434 quote!(#setter).to_string(),
435 quote!(
436 #[allow(unused_mut)]
437 pub fn foo(&mut self, value: Foo) -> &mut Self {
438 let mut new = self;
439 new.foo = ::derive_builder::export::core::option::Option::Some(
440 ::derive_builder::export::core::option::Option::Some(value)
441 );
442 new
443 }
444 )
445 .to_string()
446 );
447 }
448
449 #[test]
450 fn strip_option_into() {
451 let ty = parse_quote!(Option<Foo>);
452 let mut setter = default_setter!();
453 setter.strip_option = true;
454 setter.generic_into = true;
455 setter.field_type = BuilderFieldType::Optional(&ty);
456
457 #[rustfmt::skip]
458 assert_eq!(
459 quote!(#setter).to_string(),
460 quote!(
461 #[allow(unused_mut)]
462 pub fn foo<VALUE: ::derive_builder::export::core::convert::Into<Foo>>(
463 &mut self,
464 value: VALUE
465 ) -> &mut Self {
466 let mut new = self;
467 new.foo = ::derive_builder::export::core::option::Option::Some(
468 ::derive_builder::export::core::option::Option::Some(value.into())
469 );
470 new
471 }
472 )
473 .to_string()
474 );
475 }
476
477 #[test]
479 fn full() {
480 let attrs: Vec<syn::Attribute> = vec![parse_quote!(#[some_attr])];
483
484 let mut deprecated = DeprecationNotes::default();
485 deprecated.push("Some example.".to_string());
486
487 let mut setter = default_setter!();
488 setter.attrs = attrs.as_slice();
489 setter.generic_into = true;
490 setter.deprecation_notes = &deprecated;
491 setter.try_setter = true;
492
493 assert_eq!(
494 quote!(#setter).to_string(),
495 quote!(
496 #[some_attr]
497 #[allow(unused_mut)]
498 pub fn foo <VALUE: ::derive_builder::export::core::convert::Into<Foo>>(&mut self, value: VALUE) -> &mut Self {
499 #deprecated
500 let mut new = self;
501 new.foo = ::derive_builder::export::core::option::Option::Some(value.into());
502 new
503 }
504
505 #[some_attr]
506 pub fn try_foo<VALUE: ::derive_builder::export::core::convert::TryInto<Foo>>(&mut self, value: VALUE)
507 -> ::derive_builder::export::core::result::Result<&mut Self, VALUE::Error> {
508 let converted : Foo = value.try_into()?;
509 let mut new = self;
510 new.foo = ::derive_builder::export::core::option::Option::Some(converted);
511 Ok(new)
512 }
513 ).to_string()
514 );
515 }
516
517 #[test]
518 fn no_std() {
519 let mut setter = default_setter!();
520 setter.pattern = BuilderPattern::Immutable;
521
522 assert_eq!(
523 quote!(#setter).to_string(),
524 quote!(
525 #[allow(unused_mut)]
526 pub fn foo(&self, value: Foo) -> Self {
527 let mut new = ::derive_builder::export::core::clone::Clone::clone(self);
528 new.foo = ::derive_builder::export::core::option::Option::Some(value);
529 new
530 }
531 )
532 .to_string()
533 );
534 }
535
536 #[test]
537 fn no_std_generic() {
538 let mut setter = default_setter!();
539 setter.generic_into = true;
540
541 #[rustfmt::skip]
542 assert_eq!(
543 quote!(#setter).to_string(),
544 quote!(
545 #[allow(unused_mut)]
546 pub fn foo<VALUE: ::derive_builder::export::core::convert::Into<Foo>>(
547 &mut self,
548 value: VALUE
549 ) -> &mut Self {
550 let mut new = self;
551 new.foo = ::derive_builder::export::core::option::Option::Some(value.into());
552 new
553 }
554 )
555 .to_string()
556 );
557 }
558
559 #[test]
560 fn setter_disabled() {
561 let mut setter = default_setter!();
562 setter.setter_enabled = false;
563
564 assert_eq!(quote!(#setter).to_string(), quote!().to_string());
565 }
566
567 #[test]
568 fn try_setter() {
569 let mut setter: Setter = default_setter!();
570 setter.pattern = BuilderPattern::Mutable;
571 setter.try_setter = true;
572
573 #[rustfmt::skip]
574 assert_eq!(
575 quote!(#setter).to_string(),
576 quote!(
577 #[allow(unused_mut)]
578 pub fn foo(&mut self, value: Foo) -> &mut Self {
579 let mut new = self;
580 new.foo = ::derive_builder::export::core::option::Option::Some(value);
581 new
582 }
583
584 pub fn try_foo<VALUE: ::derive_builder::export::core::convert::TryInto<Foo>>(
585 &mut self,
586 value: VALUE
587 ) -> ::derive_builder::export::core::result::Result<&mut Self, VALUE::Error> {
588 let converted: Foo = value.try_into()?;
589 let mut new = self;
590 new.foo = ::derive_builder::export::core::option::Option::Some(converted);
591 Ok(new)
592 }
593 )
594 .to_string()
595 );
596 }
597
598 #[test]
599 fn extract_type_from_option_on_simple_type() {
600 let ty_foo = parse_quote!(Foo);
601 assert_eq!(extract_type_from_option(&ty_foo), None);
602
603 for s in vec![
604 parse_quote!(Option<Foo>),
605 parse_quote!(std::option::Option<Foo>),
606 parse_quote!(::std::option::Option<Foo>),
607 parse_quote!(core::option::Option<Foo>),
608 parse_quote!(::core::option::Option<Foo>),
609 ] {
610 assert_eq!(extract_type_from_option(&s), Some(&ty_foo));
611 }
612 }
613}