bon_macros/builder/builder_gen/
models.rs

1use super::member::Member;
2use super::top_level_config::{DerivesConfig, OnConfig};
3use crate::normalization::GenericsNamespace;
4use crate::parsing::{BonCratePath, ItemSigConfig, SpannedKey};
5use crate::util::prelude::*;
6use std::borrow::Cow;
7
8pub(super) trait FinishFnBody {
9    /// Generate the `finish` function body from the ready-made variables.
10    /// The generated function body may assume that there are variables
11    /// named the same as the members in scope.
12    fn generate(&self, ctx: &BuilderGenCtx) -> TokenStream;
13}
14
15pub(super) struct AssocMethodReceiverCtx {
16    pub(super) with_self_keyword: syn::Receiver,
17    pub(super) without_self_keyword: Box<syn::Type>,
18
19    /// Name of the receiver field in the builder struct.
20    pub(super) field_ident: syn::Ident,
21}
22
23pub(super) struct AssocMethodReceiverCtxParams {
24    pub(super) with_self_keyword: syn::Receiver,
25    pub(super) without_self_keyword: Box<syn::Type>,
26}
27
28pub(super) struct AssocMethodCtx {
29    /// The `Self` type of the impl block. It doesn't contain any nested
30    /// `Self` keywords in it. This is prohibited by Rust's syntax itself.
31    pub(super) self_ty: Box<syn::Type>,
32
33    /// Present only if the method has a receiver, i.e. `self` or `&self` or
34    /// `&mut self` or `self: ExplicitType`.
35    pub(super) receiver: Option<AssocMethodReceiverCtx>,
36}
37
38pub(super) struct AssocMethodCtxParams {
39    /// The `Self` type of the impl block. It doesn't contain any nested
40    /// `Self` keywords in it. This is prohibited by Rust's syntax itself.
41    pub(super) self_ty: Box<syn::Type>,
42
43    /// Present only if the method has a receiver, i.e. `self` or `&self` or
44    /// `&mut self` or `self: ExplicitType`.
45    pub(super) receiver: Option<AssocMethodReceiverCtxParams>,
46}
47
48pub(super) struct FinishFn {
49    pub(super) ident: syn::Ident,
50
51    /// Visibility override specified by the user
52    pub(super) vis: syn::Visibility,
53
54    /// Additional attributes to apply to the item
55    pub(super) attrs: Vec<syn::Attribute>,
56
57    pub(super) unsafety: Option<syn::Token![unsafe]>,
58    pub(super) asyncness: Option<syn::Token![async]>,
59    /// <https://doc.rust-lang.org/reference/attributes/diagnostics.html#the-must_use-attribute>
60    pub(super) must_use: Option<syn::Attribute>,
61    pub(super) body: Box<dyn FinishFnBody>,
62    pub(super) output: syn::ReturnType,
63}
64
65pub(super) struct FinishFnParams {
66    pub(super) ident: syn::Ident,
67
68    /// Visibility override specified by the user
69    pub(super) vis: Option<syn::Visibility>,
70
71    pub(super) attrs: Vec<syn::Attribute>,
72    pub(super) unsafety: Option<syn::Token![unsafe]>,
73    pub(super) asyncness: Option<syn::Token![async]>,
74    pub(super) must_use: Option<syn::Attribute>,
75    pub(super) body: Box<dyn FinishFnBody>,
76    pub(super) output: syn::ReturnType,
77}
78
79pub(super) struct StartFn {
80    pub(super) ident: syn::Ident,
81    pub(super) vis: syn::Visibility,
82
83    pub(super) docs: Vec<syn::Attribute>,
84
85    /// Overrides the default generics
86    pub(super) generics: Option<Generics>,
87}
88
89pub(super) struct StartFnParams {
90    pub(super) ident: syn::Ident,
91
92    /// If present overrides the default visibility derived from the builder's type.
93    pub(super) vis: Option<syn::Visibility>,
94
95    pub(super) docs: Vec<syn::Attribute>,
96
97    /// Overrides the default generics
98    pub(super) generics: Option<Generics>,
99}
100
101pub(super) struct BuilderType {
102    pub(super) ident: syn::Ident,
103
104    /// Visibility of the builder module itself.
105    pub(super) vis: syn::Visibility,
106
107    pub(super) derives: DerivesConfig,
108    pub(super) docs: Vec<syn::Attribute>,
109}
110
111pub(super) struct BuilderTypeParams {
112    pub(super) ident: syn::Ident,
113    pub(super) vis: Option<syn::Visibility>,
114    pub(super) derives: DerivesConfig,
115    pub(super) docs: Option<Vec<syn::Attribute>>,
116}
117
118pub(super) struct StateMod {
119    pub(super) ident: syn::Ident,
120
121    /// Visibility of the builder module itself.
122    pub(super) vis: syn::Visibility,
123
124    /// Visibility equivalent to the [`Self::vis`], but for items
125    /// generated inside the builder child module.
126    pub(super) vis_child: syn::Visibility,
127
128    /// Visibility equivalent to the [`Self::vis_child`], but for items
129    /// generated inside one more level of nesting in the builder child module.
130    pub(super) vis_child_child: syn::Visibility,
131
132    pub(super) docs: Vec<syn::Attribute>,
133}
134
135pub(super) struct Generics {
136    pub(super) where_clause: Option<syn::WhereClause>,
137
138    /// Original generics that may contain default values in them. This is only
139    /// suitable for use in places where default values for generic parameters
140    /// are allowed.
141    pub(super) decl_with_defaults: Vec<syn::GenericParam>,
142
143    /// Generic parameters without default values in them. This is suitable for
144    /// use as generics in function signatures or impl blocks.
145    pub(super) decl_without_defaults: Vec<syn::GenericParam>,
146
147    /// Mirrors the `decl` representing how generic params should be represented
148    /// when these parameters are passed through as arguments in a turbofish.
149    pub(super) args: Vec<syn::GenericArgument>,
150}
151
152pub(crate) struct BuilderGenCtx {
153    pub(super) bon: BonCratePath,
154
155    /// Name of the generic variable that holds the builder's state.
156    pub(super) state_var: syn::Ident,
157
158    pub(super) members: Vec<Member>,
159
160    /// Lint suppressions from the original item that will be inherited by all items
161    /// generated by the macro. If the original syntax used `#[expect(...)]`,
162    /// then it must be represented as `#[allow(...)]` here.
163    pub(super) allow_attrs: Vec<syn::Attribute>,
164    pub(super) on: Vec<OnConfig>,
165
166    pub(super) generics: Generics,
167
168    pub(super) assoc_method_ctx: Option<AssocMethodCtx>,
169
170    pub(super) builder_type: BuilderType,
171    pub(super) state_mod: StateMod,
172    pub(super) start_fn: StartFn,
173    pub(super) finish_fn: FinishFn,
174}
175
176pub(super) struct BuilderGenCtxParams<'a> {
177    pub(crate) bon: BonCratePath,
178    pub(super) namespace: Cow<'a, GenericsNamespace>,
179    pub(super) members: Vec<Member>,
180
181    pub(super) allow_attrs: Vec<syn::Attribute>,
182    pub(super) on: Vec<OnConfig>,
183
184    /// This is the visibility of the original item that the builder is generated for.
185    /// For example, the `struct` or `fn` item visibility that the `#[builder]` or
186    /// `#[derive(Builder)]` attribute is applied to.
187    ///
188    /// It is used as the default visibility for all the generated items unless
189    /// explicitly overridden at a more specific level.
190    pub(super) orig_item_vis: syn::Visibility,
191
192    /// Generics to apply to the builder type.
193    pub(super) generics: Generics,
194
195    pub(super) assoc_method_ctx: Option<AssocMethodCtxParams>,
196
197    pub(super) builder_type: BuilderTypeParams,
198    pub(super) state_mod: ItemSigConfig,
199    pub(super) start_fn: StartFnParams,
200    pub(super) finish_fn: FinishFnParams,
201}
202
203impl BuilderGenCtx {
204    pub(super) fn new(params: BuilderGenCtxParams<'_>) -> Result<Self> {
205        let BuilderGenCtxParams {
206            bon,
207            namespace,
208            members,
209            allow_attrs,
210            on,
211            generics,
212            orig_item_vis,
213            assoc_method_ctx,
214            builder_type,
215            state_mod,
216            start_fn,
217            finish_fn,
218        } = params;
219
220        let builder_type = BuilderType {
221            ident: builder_type.ident,
222            vis: builder_type.vis.unwrap_or(orig_item_vis),
223            derives: builder_type.derives,
224            docs: builder_type.docs.unwrap_or_else(|| {
225                let doc = format!(
226                    "Use builder syntax to set the inputs and finish with [`{0}()`](Self::{0}()).",
227                    finish_fn.ident
228                );
229
230                vec![syn::parse_quote! {
231                    #[doc = #doc]
232                }]
233            }),
234        };
235
236        let state_mod = {
237            let is_ident_overridden = state_mod.name.is_some();
238            let ident = state_mod
239                .name
240                .map(SpannedKey::into_value)
241                .unwrap_or_else(|| builder_type.ident.pascal_to_snake_case());
242
243            if builder_type.ident == ident {
244                if is_ident_overridden {
245                    bail!(
246                        &ident,
247                        "the builder module name must be different from the builder type name"
248                    )
249                }
250
251                bail!(
252                    &builder_type.ident,
253                    "couldn't infer the builder module name that doesn't conflict with \
254                    the builder type name; by default, the builder module name is set \
255                    to a snake_case equivalent of the builder type name; the snake_case \
256                    conversion doesn't produce a different name for this builder type \
257                    name; consider using PascalCase for the builder type name or specify \
258                    a separate name for the builder module explicitly via \
259                    `#[builder(state_mod = {{new_name}})]`"
260                );
261            }
262
263            // The builder module is private by default, meaning all symbols under
264            // that module can't be accessed from outside the module where the builder
265            // is defined. This makes the builder type signature unnamable from outside
266            // the module where we output the builder. The users need to explicitly
267            // opt-in to make the builder module public.
268            let vis = state_mod
269                .vis
270                .map(SpannedKey::into_value)
271                .unwrap_or_else(|| syn::Visibility::Inherited);
272
273            // The visibility for child items is based on the visibility of the
274            // builder type itself, because the types and traits from this module
275            // are part of the builder's generic type state parameter signature.
276            let vis_child = builder_type.vis.clone().into_equivalent_in_child_module()?;
277            let vis_child_child = vis_child.clone().into_equivalent_in_child_module()?;
278
279            StateMod {
280                vis,
281                vis_child,
282                vis_child_child,
283
284                ident,
285
286                docs: state_mod
287                    .docs
288                    .map(SpannedKey::into_value)
289                    .unwrap_or_else(|| {
290                        let docs = format!(
291                            "Tools for manipulating the type state of [`{}`].\n\
292                            \n\
293                            See the [detailed guide](https://bon-rs.com/guide/typestate-api) \
294                            that describes how all the pieces here fit together.",
295                            builder_type.ident
296                        );
297
298                        vec![syn::parse_quote!(#[doc = #docs])]
299                    }),
300            }
301        };
302
303        let start_fn = StartFn {
304            ident: start_fn.ident,
305            vis: start_fn.vis.unwrap_or_else(|| builder_type.vis.clone()),
306            docs: start_fn.docs,
307            generics: start_fn.generics,
308        };
309
310        let finish_fn = FinishFn {
311            ident: finish_fn.ident,
312            vis: finish_fn.vis.unwrap_or_else(|| builder_type.vis.clone()),
313            attrs: finish_fn.attrs,
314            unsafety: finish_fn.unsafety,
315            asyncness: finish_fn.asyncness,
316            must_use: finish_fn.must_use,
317            body: finish_fn.body,
318            output: finish_fn.output,
319        };
320
321        let state_var = {
322            let possible_names = ["S", "State", "BuilderState"];
323            possible_names
324                .iter()
325                .find(|&&candidate| !namespace.idents.contains(candidate))
326                .map(|&name| syn::Ident::new(name, Span::call_site()))
327                .unwrap_or_else(|| namespace.unique_ident(format!("{}_", possible_names[0])))
328        };
329
330        let assoc_method_ctx = assoc_method_ctx.map(|ctx| {
331            let receiver = ctx.receiver.map(|receiver| {
332                let start_fn_arg_names = members
333                    .iter()
334                    .filter_map(Member::as_start_fn)
335                    .map(|member| member.ident.to_string())
336                    .collect();
337
338                let field_ident = crate::normalization::unique_name(
339                    &start_fn_arg_names,
340                    "self_receiver".to_owned(),
341                );
342
343                AssocMethodReceiverCtx {
344                    with_self_keyword: receiver.with_self_keyword,
345                    without_self_keyword: receiver.without_self_keyword,
346                    field_ident: syn::Ident::new(&field_ident, Span::call_site()),
347                }
348            });
349
350            AssocMethodCtx {
351                self_ty: ctx.self_ty,
352                receiver,
353            }
354        });
355
356        Ok(Self {
357            bon,
358            state_var,
359            members,
360            allow_attrs,
361            on,
362            generics,
363            assoc_method_ctx,
364            builder_type,
365            state_mod,
366            start_fn,
367            finish_fn,
368        })
369    }
370}
371
372impl Generics {
373    pub(super) fn new(
374        decl_with_defaults: Vec<syn::GenericParam>,
375        where_clause: Option<syn::WhereClause>,
376    ) -> Self {
377        let decl_without_defaults = decl_with_defaults
378            .iter()
379            .cloned()
380            .map(|mut param| {
381                match &mut param {
382                    syn::GenericParam::Type(param) => {
383                        param.default = None;
384                    }
385                    syn::GenericParam::Const(param) => {
386                        param.default = None;
387                    }
388                    syn::GenericParam::Lifetime(_) => {}
389                }
390                param
391            })
392            .collect();
393
394        let args = decl_with_defaults
395            .iter()
396            .map(syn::GenericParam::to_generic_argument)
397            .collect();
398
399        Self {
400            where_clause,
401            decl_with_defaults,
402            decl_without_defaults,
403            args,
404        }
405    }
406
407    pub(super) fn where_clause_predicates(&self) -> impl Iterator<Item = &syn::WherePredicate> {
408        self.where_clause
409            .as_ref()
410            .into_iter()
411            .flat_map(|clause| &clause.predicates)
412    }
413}