Skip to content

Make self receiver and start_fn members available as official fields #250

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 6 additions & 14 deletions bon-macros/src/builder/builder_gen/builder_decl.rs
Original file line number Diff line number Diff line change
Expand Up @@ -37,10 +37,10 @@ impl super::BuilderGenCtx {
};

let receiver_field = self.receiver().map(|receiver| {
let ident = &receiver.field_ident;
let ty = &receiver.without_self_keyword;
quote! {
#private_field_attrs
__unsafe_private_receiver: #ty,
#ident: #ty,
}
});

Expand All @@ -51,17 +51,8 @@ impl super::BuilderGenCtx {

let allows = super::allow_warnings_on_member_types();

let mut start_fn_arg_types = self
.start_fn_args()
.map(|member| &member.base.ty.norm)
.peekable();

let start_fn_args_field = start_fn_arg_types.peek().is_some().then(|| {
quote! {
#private_field_attrs
__unsafe_private_start_fn_args: (#(#start_fn_arg_types,)*),
}
});
let start_fn_args_fields_idents = self.start_fn_args().map(|member| &member.ident);
let start_fn_args_fields_types = self.start_fn_args().map(|member| &member.ty.norm);

let named_members_types = self.named_members().map(NamedMember::underlying_norm_ty);

Expand Down Expand Up @@ -104,7 +95,8 @@ impl super::BuilderGenCtx {
__unsafe_private_phantom: #phantom_data,

#receiver_field
#start_fn_args_field

#( #start_fn_args_fields_idents: #start_fn_args_fields_types, )*

#( #custom_fields_idents: #custom_fields_types, )*

Expand Down
25 changes: 10 additions & 15 deletions bon-macros/src/builder/builder_gen/builder_derives/clone.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,27 +12,22 @@ impl BuilderGenCtx {
let clone = quote!(::core::clone::Clone);

let clone_receiver = self.receiver().map(|receiver| {
let ident = &receiver.field_ident;
let ty = &receiver.without_self_keyword;
quote! {
__unsafe_private_receiver: <#ty as #clone>::clone(&self.__unsafe_private_receiver),
#ident: <#ty as #clone>::clone(&self.#ident),
}
});

let clone_start_fn_args = self.start_fn_args().next().map(|_| {
let types = self.start_fn_args().map(|arg| &arg.base.ty.norm);
let indices = self.start_fn_args().map(|arg| &arg.index);
let clone_start_fn_args = self.start_fn_args().map(|member| {
let member_ident = &member.ident;
let member_ty = &member.ty.norm;

quote! {
// We clone named members individually instead of cloning
// the entire tuple to improve error messages in case if
// one of the members doesn't implement `Clone`. This avoids
// a sentence that say smth like
// ```
// required for `(...big type...)` to implement `Clone`
// ```
__unsafe_private_start_fn_args: (
#( <#types as #clone>::clone(&self.__unsafe_private_start_fn_args.#indices), )*
),
// The type hint here is necessary to get better error messages
// that point directly to the type that doesn't implement `Clone`
// in the input code using the span info from the type hint.
#member_ident: <#member_ty as #clone>::clone(&self.#member_ident)
}
});

Expand Down Expand Up @@ -84,7 +79,7 @@ impl BuilderGenCtx {
Self {
__unsafe_private_phantom: ::core::marker::PhantomData,
#clone_receiver
#clone_start_fn_args
#( #clone_start_fn_args, )*
#( #clone_fields, )*

// We clone named members individually instead of cloning
Expand Down
14 changes: 8 additions & 6 deletions bon-macros/src/builder/builder_gen/builder_derives/debug.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,14 +10,14 @@ impl BuilderGenCtx {
let format_members = self.members.iter().filter_map(|member| {
match member {
Member::StartFn(member) => {
let member_index = &member.index;
let member_ident_str = member.base.ident.to_string();
let member_ty = &member.base.ty.norm;
let member_ident = &member.ident;
let member_ident_str = member_ident.to_string();
let member_ty = &member.ty.norm;
Some(quote! {
output.field(
#member_ident_str,
#bon::__::better_errors::as_dyn_debug::<#member_ty>(
&self.__unsafe_private_start_fn_args.#member_index
&self.#member_ident
)
);
})
Expand Down Expand Up @@ -57,12 +57,14 @@ impl BuilderGenCtx {
});

let format_receiver = self.receiver().map(|receiver| {
let ident = &receiver.field_ident;
let ident_str = ident.to_string();
let ty = &receiver.without_self_keyword;
quote! {
output.field(
"self",
#ident_str,
#bon::__::better_errors::as_dyn_debug::<#ty>(
&self.__unsafe_private_receiver
&self.#ident
)
);
}
Expand Down
5 changes: 2 additions & 3 deletions bon-macros/src/builder/builder_gen/finish_fn.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,8 @@ impl super::BuilderGenCtx {
.unwrap_or_else(|| quote! { ::core::default::Default::default() });
}
Member::StartFn(member) => {
let index = &member.index;

return quote! { self.__unsafe_private_start_fn_args.#index };
let ident = &member.ident;
return quote! { self.#ident };
}
Member::FinishFn(member) => {
return member
Expand Down
26 changes: 14 additions & 12 deletions bon-macros/src/builder/builder_gen/input_fn.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,7 @@
use super::models::FinishFnParams;
use super::models::{AssocMethodReceiverCtxParams, FinishFnParams};
use super::top_level_config::TopLevelConfig;
use super::{
AssocMethodCtx, AssocMethodReceiverCtx, BuilderGenCtx, FinishFnBody, Generics, Member,
MemberOrigin, RawMember,
AssocMethodCtxParams, BuilderGenCtx, FinishFnBody, Generics, Member, MemberOrigin, RawMember,
};
use crate::builder::builder_gen::models::{BuilderGenCtxParams, BuilderTypeParams, StartFnParams};
use crate::normalization::{GenericsNamespace, NormalizeSelfTy, SyntaxVariant};
Expand Down Expand Up @@ -122,19 +121,19 @@ impl<'a> FnInputCtx<'a> {
}
}

fn assoc_method_ctx(&self) -> Result<Option<AssocMethodCtx>> {
fn assoc_method_ctx(&self) -> Result<Option<AssocMethodCtxParams>> {
let self_ty = match self.impl_ctx.as_deref() {
Some(impl_ctx) => impl_ctx.self_ty.clone(),
None => return Ok(None),
};

Ok(Some(AssocMethodCtx {
Ok(Some(AssocMethodCtxParams {
self_ty,
receiver: self.assoc_method_receiver_ctx()?,
receiver: self.assoc_method_receiver_ctx_params()?,
}))
}

fn assoc_method_receiver_ctx(&self) -> Result<Option<AssocMethodReceiverCtx>> {
fn assoc_method_receiver_ctx_params(&self) -> Result<Option<AssocMethodReceiverCtxParams>> {
let receiver = match self.fn_item.norm.sig.receiver() {
Some(receiver) => receiver,
None => return Ok(None),
Expand All @@ -161,7 +160,7 @@ impl<'a> FnInputCtx<'a> {

NormalizeSelfTy { self_ty }.visit_type_mut(&mut without_self_keyword);

Ok(Some(AssocMethodReceiverCtx {
Ok(Some(AssocMethodReceiverCtxParams {
with_self_keyword: receiver.clone(),
without_self_keyword,
}))
Expand Down Expand Up @@ -451,10 +450,13 @@ impl FinishFnBody for FnCallBody {
.filter(|arg| !matches!(arg, syn::GenericParam::Lifetime(_)))
.map(syn::GenericParam::to_generic_argument);

let prefix = self
.sig
.receiver()
.map(|_| quote!(self.__unsafe_private_receiver.))
let prefix = ctx
.assoc_method_ctx
.as_ref()
.and_then(|ctx| {
let ident = &ctx.receiver.as_ref()?.field_ident;
Some(quote!(self.#ident.))
})
.or_else(|| {
let self_ty = &self.impl_ctx.as_deref()?.self_ty;
Some(quote!(<#self_ty>::))
Expand Down
4 changes: 2 additions & 2 deletions bon-macros/src/builder/builder_gen/input_struct.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
use super::models::FinishFnParams;
use super::top_level_config::TopLevelConfig;
use super::{
AssocMethodCtx, BuilderGenCtx, FinishFnBody, Generics, Member, MemberOrigin, RawMember,
AssocMethodCtxParams, BuilderGenCtx, FinishFnBody, Generics, Member, MemberOrigin, RawMember,
};
use crate::builder::builder_gen::models::{BuilderGenCtxParams, BuilderTypeParams, StartFnParams};
use crate::normalization::{GenericsNamespace, SyntaxVariant};
Expand Down Expand Up @@ -193,7 +193,7 @@ impl StructInputCtx {
generics: None,
};

let assoc_method_ctx = Some(AssocMethodCtx {
let assoc_method_ctx = Some(AssocMethodCtxParams {
self_ty: self.struct_ty.into(),
receiver: None,
});
Expand Down
41 changes: 10 additions & 31 deletions bon-macros/src/builder/builder_gen/member/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ impl MemberOrigin {
#[derive(Debug)]
pub(crate) enum Member {
/// Member that was marked with `#[builder(start_fn)]`
StartFn(StartFnMember),
StartFn(PosFnMember),

/// Member that was marked with `#[builder(field)]`
Field(CustomField),
Expand All @@ -54,15 +54,6 @@ pub(crate) enum Member {
Skip(SkipMember),
}

/// Member that was marked with `#[builder(start_fn)]`
#[derive(Debug)]
pub(crate) struct StartFnMember {
pub(crate) base: PosFnMember,

/// Index of the member relative to other positional members. The index is 0-based.
pub(crate) index: syn::Index,
}

#[derive(Debug)]
pub(crate) struct CustomField {
pub(crate) ident: syn::Ident,
Expand Down Expand Up @@ -138,21 +129,13 @@ impl Member {
let mut output = vec![];

// Collect `start_fn` members
for index in 0.. {
let next = members.next_if(|(_, meta)| meta.start_fn.is_present());
let (member, config) = match next {
Some(item) => item,
None => break,
};
let base = PosFnMember::new(origin, member, on, config)?;
output.push(Self::StartFn(StartFnMember {
base,
index: index.into(),
}));
while let Some((member, config)) = members.next_if(|(_, cfg)| cfg.start_fn.is_present()) {
let member = PosFnMember::new(origin, member, on, config)?;
output.push(Self::StartFn(member));
}

// Collect `field` members
while let Some((member, config)) = members.next_if(|(_, config)| config.field.is_some()) {
while let Some((member, config)) = members.next_if(|(_, cfg)| cfg.field.is_some()) {
let init = config
.field
.expect("validated `field.is_some()` in `next_if`")
Expand All @@ -163,10 +146,8 @@ impl Member {
}

// Collect `finish_fn` members
while let Some((member, config)) =
members.next_if(|(_, config)| config.finish_fn.is_present())
{
let member = PosFnMember::new(origin, member, on, config)?;
while let Some((member, cfg)) = members.next_if(|(_, cfg)| cfg.finish_fn.is_present()) {
let member = PosFnMember::new(origin, member, on, cfg)?;
output.push(Self::FinishFn(member));
}

Expand Down Expand Up @@ -238,19 +219,17 @@ impl Member {
impl Member {
pub(crate) fn norm_ty(&self) -> &syn::Type {
match self {
Self::StartFn(me) => &me.base.ty.norm,
Self::Field(me) => &me.norm_ty,
Self::FinishFn(me) => &me.ty.norm,
Self::FinishFn(me) | Self::StartFn(me) => &me.ty.norm,
Self::Named(me) => &me.ty.norm,
Self::Skip(me) => &me.norm_ty,
}
}

pub(crate) fn orig_ident(&self) -> &syn::Ident {
match self {
Self::StartFn(me) => &me.base.ident,
Self::Field(me) => &me.ident,
Self::FinishFn(me) => &me.ident,
Self::FinishFn(me) | Self::StartFn(me) => &me.ident,
Self::Named(me) => &me.name.orig,
Self::Skip(me) => &me.ident,
}
Expand All @@ -270,7 +249,7 @@ impl Member {
}
}

pub(crate) fn as_start_fn(&self) -> Option<&StartFnMember> {
pub(crate) fn as_start_fn(&self) -> Option<&PosFnMember> {
match self {
Self::StartFn(me) => Some(me),
_ => None,
Expand Down
8 changes: 3 additions & 5 deletions bon-macros/src/builder/builder_gen/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,10 +15,8 @@ pub(crate) use top_level_config::TopLevelConfig;

use crate::util::prelude::*;
use getters::GettersCtx;
use member::{
CustomField, Member, MemberOrigin, NamedMember, PosFnMember, RawMember, StartFnMember,
};
use models::{AssocMethodCtx, AssocMethodReceiverCtx, BuilderGenCtx, FinishFnBody, Generics};
use member::{CustomField, Member, MemberOrigin, NamedMember, PosFnMember, RawMember};
use models::{AssocMethodCtxParams, AssocMethodReceiverCtx, BuilderGenCtx, FinishFnBody, Generics};
use setters::SettersCtx;

pub(crate) struct MacroOutput {
Expand All @@ -39,7 +37,7 @@ impl BuilderGenCtx {
self.members.iter().filter_map(Member::as_field)
}

fn start_fn_args(&self) -> impl Iterator<Item = &StartFnMember> {
fn start_fn_args(&self) -> impl Iterator<Item = &PosFnMember> {
self.members.iter().filter_map(Member::as_start_fn)
}

Expand Down
Loading