typed_builder_macro/
builder_attr.rs
1use proc_macro2::TokenStream;
2use quote::{quote, ToTokens};
3use syn::parse::Error;
4
5use crate::field_info::FieldBuilderAttr;
6use crate::mutator::Mutator;
7use crate::util::{path_to_single_string, ApplyMeta, AttrArg};
8
9#[derive(Debug, Default, Clone)]
10pub struct CommonDeclarationSettings {
11 pub vis: Option<syn::Visibility>,
12 pub name: Option<syn::Expr>,
13 pub doc: Option<syn::Expr>,
14}
15
16impl ApplyMeta for CommonDeclarationSettings {
17 fn apply_meta(&mut self, expr: AttrArg) -> Result<(), Error> {
18 match expr.name().to_string().as_str() {
19 "vis" => {
20 let expr_str = expr.key_value()?.parse_value::<syn::LitStr>()?.value();
21 self.vis = Some(syn::parse_str(&expr_str)?);
22 Ok(())
23 }
24 "name" => {
25 self.name = Some(expr.key_value()?.parse_value()?);
26 Ok(())
27 }
28 "doc" => {
29 self.doc = Some(expr.key_value()?.parse_value()?);
30 Ok(())
31 }
32 _ => Err(Error::new_spanned(
33 expr.name(),
34 format!("Unknown parameter {:?}", expr.name().to_string()),
35 )),
36 }
37 }
38}
39
40impl CommonDeclarationSettings {
41 pub fn get_name(&self) -> Option<TokenStream> {
42 self.name.as_ref().map(|name| name.to_token_stream())
43 }
44
45 pub fn get_doc_or(&self, gen_doc: impl FnOnce() -> String) -> TokenStream {
46 if let Some(ref doc) = self.doc {
47 quote!(#[doc = #doc])
48 } else {
49 let doc = gen_doc();
50 quote!(#[doc = #doc])
51 }
52 }
53}
54
55#[derive(Debug, Clone)]
57pub enum IntoSetting {
58 NoConversion,
60 GenericConversion,
62 TypeConversionToSpecificType(syn::TypePath),
64}
65
66impl Default for IntoSetting {
67 fn default() -> Self {
68 Self::NoConversion
69 }
70}
71
72#[derive(Debug, Default, Clone)]
73pub struct BuildMethodSettings {
74 pub common: CommonDeclarationSettings,
75
76 pub into: IntoSetting,
78}
79
80impl ApplyMeta for BuildMethodSettings {
81 fn apply_meta(&mut self, expr: AttrArg) -> Result<(), Error> {
82 match expr.name().to_string().as_str() {
83 "into" => match expr {
84 AttrArg::Flag(_) => {
85 self.into = IntoSetting::GenericConversion;
86 Ok(())
87 }
88 AttrArg::KeyValue(key_value) => {
89 let type_path = key_value.parse_value::<syn::TypePath>()?;
90 self.into = IntoSetting::TypeConversionToSpecificType(type_path);
91 Ok(())
92 }
93 _ => Err(expr.incorrect_type()),
94 },
95 _ => self.common.apply_meta(expr),
96 }
97 }
98}
99
100#[derive(Debug)]
101pub struct TypeBuilderAttr<'a> {
102 pub doc: bool,
104
105 pub builder_method: CommonDeclarationSettings,
107
108 pub builder_type: CommonDeclarationSettings,
110
111 pub build_method: BuildMethodSettings,
113
114 pub field_defaults: FieldBuilderAttr<'a>,
115
116 pub crate_module_path: syn::Path,
117
118 pub mutators: Vec<Mutator>,
120}
121
122impl Default for TypeBuilderAttr<'_> {
123 fn default() -> Self {
124 Self {
125 doc: Default::default(),
126 builder_method: Default::default(),
127 builder_type: Default::default(),
128 build_method: Default::default(),
129 field_defaults: Default::default(),
130 crate_module_path: syn::parse_quote!(::typed_builder),
131 mutators: Default::default(),
132 }
133 }
134}
135
136impl<'a> TypeBuilderAttr<'a> {
137 pub fn new(attrs: &[syn::Attribute]) -> Result<Self, Error> {
138 let mut result = Self::default();
139
140 for attr in attrs {
141 let list = match &attr.meta {
142 syn::Meta::List(list) => {
143 if path_to_single_string(&list.path).as_deref() != Some("builder") {
144 continue;
145 }
146
147 list
148 }
149 _ => continue,
150 };
151
152 result.apply_subsections(list)?;
153 }
154
155 if result.builder_type.doc.is_some() || result.build_method.common.doc.is_some() {
156 result.doc = true;
157 }
158
159 Ok(result)
160 }
161}
162
163impl ApplyMeta for TypeBuilderAttr<'_> {
164 fn apply_meta(&mut self, expr: AttrArg) -> Result<(), Error> {
165 match expr.name().to_string().as_str() {
166 "crate_module_path" => {
167 let crate_module_path = expr.key_value()?.parse_value::<syn::ExprPath>()?;
168 self.crate_module_path = crate_module_path.path;
169 Ok(())
170 }
171 "builder_method_doc" => Err(Error::new_spanned(
172 expr.name(),
173 "`builder_method_doc` is deprecated - use `builder_method(doc = \"...\")`",
174 )),
175 "builder_type_doc" => Err(Error::new_spanned(
176 expr.name(),
177 "`builder_typemethod_doc` is deprecated - use `builder_type(doc = \"...\")`",
178 )),
179 "build_method_doc" => Err(Error::new_spanned(
180 expr.name(),
181 "`build_method_doc` is deprecated - use `build_method(doc = \"...\")`",
182 )),
183 "doc" => {
184 expr.flag()?;
185 self.doc = true;
186 Ok(())
187 }
188 "mutators" => {
189 self.mutators.extend(expr.sub_attr()?.undelimited()?);
190 Ok(())
191 }
192 "field_defaults" => self.field_defaults.apply_sub_attr(expr.sub_attr()?),
193 "builder_method" => self.builder_method.apply_sub_attr(expr.sub_attr()?),
194 "builder_type" => self.builder_type.apply_sub_attr(expr.sub_attr()?),
195 "build_method" => self.build_method.apply_sub_attr(expr.sub_attr()?),
196 _ => Err(Error::new_spanned(
197 expr.name(),
198 format!("Unknown parameter {:?}", expr.name().to_string()),
199 )),
200 }
201 }
202}