bon_macros/builder/builder_gen/member/into_conversion.rs
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
use super::config::{BlanketParamName, EvalBlanketFlagParam};
use super::{NamedMember, PosFnMember};
use crate::builder::builder_gen::top_level_config::OnConfig;
use crate::util::prelude::*;
impl NamedMember {
pub(super) fn merge_config_into(&mut self, on: &[OnConfig]) -> Result {
// `with` is mutually exclusive with `into`. So there is nothing to merge here
// if `with` is present.
if self.config.with.is_some() {
return Ok(());
}
// For optional named members the target of the `Into` conversion is the type
// inside of the `Option<T>`, not the `Option<T>` itself because we generate
// a setter that accepts `T` itself. It also makes this logic stable regardless
// if `Option<T>` is used or the member of type `T` has `#[builder(default)]` on it.
let scrutinee = self.underlying_orig_ty();
self.config.into = EvalBlanketFlagParam {
on,
param_name: BlanketParamName::Into,
member_config: &self.config,
scrutinee,
origin: self.origin,
}
.eval()?;
Ok(())
}
}
impl PosFnMember {
pub(crate) fn merge_config_into(&mut self, on: &[OnConfig]) -> Result {
// Positional members are never optional. Users must always specify them, so there
// is no need for us to look into the `Option<T>` generic parameter, because the
// `Option<T>` itself is the target of the into conversion, not the `T` inside it.
let scrutinee = self.ty.orig.as_ref();
self.config.into = EvalBlanketFlagParam {
on,
param_name: BlanketParamName::Into,
member_config: &self.config,
scrutinee,
origin: self.origin,
}
.eval()?;
Ok(())
}
pub(crate) fn fn_input_param(&self) -> TokenStream {
let ty = &self.ty.norm;
let ident = &self.ident;
if self.config.into.is_present() {
quote! { #ident: impl Into<#ty> }
} else {
quote! { #ident: #ty }
}
}
pub(crate) fn conversion(&self) -> Option<TokenStream> {
if !self.config.into.is_present() {
return None;
}
let ident = &self.ident;
Some(quote! { Into::into(#ident) })
}
}