1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
use proc_macro2::{
Span as Span2,
TokenStream as TokenStream2,
};
use quote::quote;
use syn::{
GenericArgument,
Ident,
PathArguments,
Type,
};
use super::setter_configs::SetterConfigs;
pub fn make_setter_methods(
setter_configs: SetterConfigs,
) -> Vec<TokenStream2> {
let mut setter_methods: Vec<TokenStream2> = Vec::new();
for (field, field_setter_configs) in setter_configs.iter() {
let field_name = &field.ident;
let field_type = &field.ty;
let span = Span2::call_site();
for field_setter_config in field_setter_configs {
let method_name = Ident::new(field_setter_config.name(), span);
let method_visibility = field_setter_config.visibility();
let with_into = field_setter_config.with_into();
let option_inner_type = extract_option_inner_type(field_type);
let setter_method = match option_inner_type {
Some(inner_type) => {
if with_into {
quote! {
#[must_use]
#method_visibility fn #method_name(
mut self,
#field_name: impl Into<#inner_type>,
) -> Self {
self.#field_name = Some(#field_name.into());
self
}
}
} else {
quote! {
#[must_use]
#method_visibility fn #method_name(
mut self,
#field_name: #inner_type,
) -> Self {
self.#field_name = Some(#field_name);
self
}
}
}
}
None => {
if with_into {
quote! {
#[must_use]
#method_visibility fn #method_name(
mut self,
#field_name: impl Into<#field_type>,
) -> Self {
self.#field_name = #field_name.into();
self
}
}
} else {
quote! {
#[must_use]
#method_visibility fn #method_name(
mut self,
#field_name: #field_type,
) -> Self {
self.#field_name = #field_name;
self
}
}
}
}
};
setter_methods.push(setter_method);
}
}
setter_methods
}
fn extract_option_inner_type(field_type: &Type) -> Option<&Type> {
if let Type::Path(type_path) = field_type {
if type_path.path.segments.is_empty() {
return None;
}
if type_path.path.segments[0].ident == "Option" {
if let PathArguments::AngleBracketed(args) =
&type_path.path.segments[0].arguments
{
if let Some(GenericArgument::Type(inner_type)) =
args.args.first()
{
return Some(inner_type);
}
}
}
}
None
}