bon_macros/builder/builder_gen/member/
into_conversion.rs

1use super::config::{BlanketParamName, EvalBlanketFlagParam};
2use super::{NamedMember, PosFnMember};
3use crate::builder::builder_gen::top_level_config::OnConfig;
4use crate::util::prelude::*;
5
6impl NamedMember {
7    pub(super) fn merge_config_into(&mut self, on: &[OnConfig]) -> Result {
8        // `with` is mutually exclusive with `into`. So there is nothing to merge here
9        // if `with` is present.
10        if self.config.with.is_some() {
11            return Ok(());
12        }
13
14        // For optional named members the target of the `Into` conversion is the type
15        // inside of the `Option<T>`, not the `Option<T>` itself because we generate
16        // a setter that accepts `T` itself. It also makes this logic stable regardless
17        // if `Option<T>` is used or the member of type `T` has `#[builder(default)]` on it.
18        let scrutinee = self.underlying_orig_ty();
19
20        self.config.into = EvalBlanketFlagParam {
21            on,
22            param_name: BlanketParamName::Into,
23            member_config: &self.config,
24            scrutinee,
25            origin: self.origin,
26        }
27        .eval()?;
28
29        Ok(())
30    }
31}
32
33impl PosFnMember {
34    pub(crate) fn merge_config_into(&mut self, on: &[OnConfig]) -> Result {
35        // Positional members are never optional. Users must always specify them, so there
36        // is no need for us to look into the `Option<T>` generic parameter, because the
37        // `Option<T>` itself is the target of the into conversion, not the `T` inside it.
38        let scrutinee = self.ty.orig.as_ref();
39
40        self.config.into = EvalBlanketFlagParam {
41            on,
42            param_name: BlanketParamName::Into,
43            member_config: &self.config,
44            scrutinee,
45            origin: self.origin,
46        }
47        .eval()?;
48
49        Ok(())
50    }
51
52    pub(crate) fn fn_input_param(&self) -> TokenStream {
53        let ty = &self.ty.norm;
54        let ident = &self.ident;
55
56        if self.config.into.is_present() {
57            quote! { #ident: impl Into<#ty> }
58        } else {
59            quote! { #ident: #ty }
60        }
61    }
62
63    pub(crate) fn conversion(&self) -> Option<TokenStream> {
64        if !self.config.into.is_present() {
65            return None;
66        }
67
68        let ident = &self.ident;
69
70        Some(quote! { Into::into(#ident) })
71    }
72}