Skip to content

Commit 72b058d

Browse files
authored
Make self receiver and start_fn members available as official fields (#250)
This is according to my design decision here: #225 (comment)
1 parent d705cc2 commit 72b058d

File tree

25 files changed

+445
-173
lines changed

25 files changed

+445
-173
lines changed

bon-macros/src/builder/builder_gen/builder_decl.rs

Lines changed: 6 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -37,10 +37,10 @@ impl super::BuilderGenCtx {
3737
};
3838

3939
let receiver_field = self.receiver().map(|receiver| {
40+
let ident = &receiver.field_ident;
4041
let ty = &receiver.without_self_keyword;
4142
quote! {
42-
#private_field_attrs
43-
__unsafe_private_receiver: #ty,
43+
#ident: #ty,
4444
}
4545
});
4646

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

5252
let allows = super::allow_warnings_on_member_types();
5353

54-
let mut start_fn_arg_types = self
55-
.start_fn_args()
56-
.map(|member| &member.base.ty.norm)
57-
.peekable();
58-
59-
let start_fn_args_field = start_fn_arg_types.peek().is_some().then(|| {
60-
quote! {
61-
#private_field_attrs
62-
__unsafe_private_start_fn_args: (#(#start_fn_arg_types,)*),
63-
}
64-
});
54+
let start_fn_args_fields_idents = self.start_fn_args().map(|member| &member.ident);
55+
let start_fn_args_fields_types = self.start_fn_args().map(|member| &member.ty.norm);
6556

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

@@ -104,7 +95,8 @@ impl super::BuilderGenCtx {
10495
__unsafe_private_phantom: #phantom_data,
10596

10697
#receiver_field
107-
#start_fn_args_field
98+
99+
#( #start_fn_args_fields_idents: #start_fn_args_fields_types, )*
108100

109101
#( #custom_fields_idents: #custom_fields_types, )*
110102

bon-macros/src/builder/builder_gen/builder_derives/clone.rs

Lines changed: 10 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -12,27 +12,22 @@ impl BuilderGenCtx {
1212
let clone = quote!(::core::clone::Clone);
1313

1414
let clone_receiver = self.receiver().map(|receiver| {
15+
let ident = &receiver.field_ident;
1516
let ty = &receiver.without_self_keyword;
1617
quote! {
17-
__unsafe_private_receiver: <#ty as #clone>::clone(&self.__unsafe_private_receiver),
18+
#ident: <#ty as #clone>::clone(&self.#ident),
1819
}
1920
});
2021

21-
let clone_start_fn_args = self.start_fn_args().next().map(|_| {
22-
let types = self.start_fn_args().map(|arg| &arg.base.ty.norm);
23-
let indices = self.start_fn_args().map(|arg| &arg.index);
22+
let clone_start_fn_args = self.start_fn_args().map(|member| {
23+
let member_ident = &member.ident;
24+
let member_ty = &member.ty.norm;
2425

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

@@ -84,7 +79,7 @@ impl BuilderGenCtx {
8479
Self {
8580
__unsafe_private_phantom: ::core::marker::PhantomData,
8681
#clone_receiver
87-
#clone_start_fn_args
82+
#( #clone_start_fn_args, )*
8883
#( #clone_fields, )*
8984

9085
// We clone named members individually instead of cloning

bon-macros/src/builder/builder_gen/builder_derives/debug.rs

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -10,14 +10,14 @@ impl BuilderGenCtx {
1010
let format_members = self.members.iter().filter_map(|member| {
1111
match member {
1212
Member::StartFn(member) => {
13-
let member_index = &member.index;
14-
let member_ident_str = member.base.ident.to_string();
15-
let member_ty = &member.base.ty.norm;
13+
let member_ident = &member.ident;
14+
let member_ident_str = member_ident.to_string();
15+
let member_ty = &member.ty.norm;
1616
Some(quote! {
1717
output.field(
1818
#member_ident_str,
1919
#bon::__::better_errors::as_dyn_debug::<#member_ty>(
20-
&self.__unsafe_private_start_fn_args.#member_index
20+
&self.#member_ident
2121
)
2222
);
2323
})
@@ -57,12 +57,14 @@ impl BuilderGenCtx {
5757
});
5858

5959
let format_receiver = self.receiver().map(|receiver| {
60+
let ident = &receiver.field_ident;
61+
let ident_str = ident.to_string();
6062
let ty = &receiver.without_self_keyword;
6163
quote! {
6264
output.field(
63-
"self",
65+
#ident_str,
6466
#bon::__::better_errors::as_dyn_debug::<#ty>(
65-
&self.__unsafe_private_receiver
67+
&self.#ident
6668
)
6769
);
6870
}

bon-macros/src/builder/builder_gen/finish_fn.rs

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -13,9 +13,8 @@ impl super::BuilderGenCtx {
1313
.unwrap_or_else(|| quote! { ::core::default::Default::default() });
1414
}
1515
Member::StartFn(member) => {
16-
let index = &member.index;
17-
18-
return quote! { self.__unsafe_private_start_fn_args.#index };
16+
let ident = &member.ident;
17+
return quote! { self.#ident };
1918
}
2019
Member::FinishFn(member) => {
2120
return member

bon-macros/src/builder/builder_gen/input_fn.rs

Lines changed: 14 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,7 @@
1-
use super::models::FinishFnParams;
1+
use super::models::{AssocMethodReceiverCtxParams, FinishFnParams};
22
use super::top_level_config::TopLevelConfig;
33
use super::{
4-
AssocMethodCtx, AssocMethodReceiverCtx, BuilderGenCtx, FinishFnBody, Generics, Member,
5-
MemberOrigin, RawMember,
4+
AssocMethodCtxParams, BuilderGenCtx, FinishFnBody, Generics, Member, MemberOrigin, RawMember,
65
};
76
use crate::builder::builder_gen::models::{BuilderGenCtxParams, BuilderTypeParams, StartFnParams};
87
use crate::normalization::{GenericsNamespace, NormalizeSelfTy, SyntaxVariant};
@@ -122,19 +121,19 @@ impl<'a> FnInputCtx<'a> {
122121
}
123122
}
124123

125-
fn assoc_method_ctx(&self) -> Result<Option<AssocMethodCtx>> {
124+
fn assoc_method_ctx(&self) -> Result<Option<AssocMethodCtxParams>> {
126125
let self_ty = match self.impl_ctx.as_deref() {
127126
Some(impl_ctx) => impl_ctx.self_ty.clone(),
128127
None => return Ok(None),
129128
};
130129

131-
Ok(Some(AssocMethodCtx {
130+
Ok(Some(AssocMethodCtxParams {
132131
self_ty,
133-
receiver: self.assoc_method_receiver_ctx()?,
132+
receiver: self.assoc_method_receiver_ctx_params()?,
134133
}))
135134
}
136135

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

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

164-
Ok(Some(AssocMethodReceiverCtx {
163+
Ok(Some(AssocMethodReceiverCtxParams {
165164
with_self_keyword: receiver.clone(),
166165
without_self_keyword,
167166
}))
@@ -451,10 +450,13 @@ impl FinishFnBody for FnCallBody {
451450
.filter(|arg| !matches!(arg, syn::GenericParam::Lifetime(_)))
452451
.map(syn::GenericParam::to_generic_argument);
453452

454-
let prefix = self
455-
.sig
456-
.receiver()
457-
.map(|_| quote!(self.__unsafe_private_receiver.))
453+
let prefix = ctx
454+
.assoc_method_ctx
455+
.as_ref()
456+
.and_then(|ctx| {
457+
let ident = &ctx.receiver.as_ref()?.field_ident;
458+
Some(quote!(self.#ident.))
459+
})
458460
.or_else(|| {
459461
let self_ty = &self.impl_ctx.as_deref()?.self_ty;
460462
Some(quote!(<#self_ty>::))

bon-macros/src/builder/builder_gen/input_struct.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
use super::models::FinishFnParams;
22
use super::top_level_config::TopLevelConfig;
33
use super::{
4-
AssocMethodCtx, BuilderGenCtx, FinishFnBody, Generics, Member, MemberOrigin, RawMember,
4+
AssocMethodCtxParams, BuilderGenCtx, FinishFnBody, Generics, Member, MemberOrigin, RawMember,
55
};
66
use crate::builder::builder_gen::models::{BuilderGenCtxParams, BuilderTypeParams, StartFnParams};
77
use crate::normalization::{GenericsNamespace, SyntaxVariant};
@@ -193,7 +193,7 @@ impl StructInputCtx {
193193
generics: None,
194194
};
195195

196-
let assoc_method_ctx = Some(AssocMethodCtx {
196+
let assoc_method_ctx = Some(AssocMethodCtxParams {
197197
self_ty: self.struct_ty.into(),
198198
receiver: None,
199199
});

bon-macros/src/builder/builder_gen/member/mod.rs

Lines changed: 10 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@ impl MemberOrigin {
3939
#[derive(Debug)]
4040
pub(crate) enum Member {
4141
/// Member that was marked with `#[builder(start_fn)]`
42-
StartFn(StartFnMember),
42+
StartFn(PosFnMember),
4343

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

57-
/// Member that was marked with `#[builder(start_fn)]`
58-
#[derive(Debug)]
59-
pub(crate) struct StartFnMember {
60-
pub(crate) base: PosFnMember,
61-
62-
/// Index of the member relative to other positional members. The index is 0-based.
63-
pub(crate) index: syn::Index,
64-
}
65-
6657
#[derive(Debug)]
6758
pub(crate) struct CustomField {
6859
pub(crate) ident: syn::Ident,
@@ -138,21 +129,13 @@ impl Member {
138129
let mut output = vec![];
139130

140131
// Collect `start_fn` members
141-
for index in 0.. {
142-
let next = members.next_if(|(_, meta)| meta.start_fn.is_present());
143-
let (member, config) = match next {
144-
Some(item) => item,
145-
None => break,
146-
};
147-
let base = PosFnMember::new(origin, member, on, config)?;
148-
output.push(Self::StartFn(StartFnMember {
149-
base,
150-
index: index.into(),
151-
}));
132+
while let Some((member, config)) = members.next_if(|(_, cfg)| cfg.start_fn.is_present()) {
133+
let member = PosFnMember::new(origin, member, on, config)?;
134+
output.push(Self::StartFn(member));
152135
}
153136

154137
// Collect `field` members
155-
while let Some((member, config)) = members.next_if(|(_, config)| config.field.is_some()) {
138+
while let Some((member, config)) = members.next_if(|(_, cfg)| cfg.field.is_some()) {
156139
let init = config
157140
.field
158141
.expect("validated `field.is_some()` in `next_if`")
@@ -163,10 +146,8 @@ impl Member {
163146
}
164147

165148
// Collect `finish_fn` members
166-
while let Some((member, config)) =
167-
members.next_if(|(_, config)| config.finish_fn.is_present())
168-
{
169-
let member = PosFnMember::new(origin, member, on, config)?;
149+
while let Some((member, cfg)) = members.next_if(|(_, cfg)| cfg.finish_fn.is_present()) {
150+
let member = PosFnMember::new(origin, member, on, cfg)?;
170151
output.push(Self::FinishFn(member));
171152
}
172153

@@ -238,19 +219,17 @@ impl Member {
238219
impl Member {
239220
pub(crate) fn norm_ty(&self) -> &syn::Type {
240221
match self {
241-
Self::StartFn(me) => &me.base.ty.norm,
242222
Self::Field(me) => &me.norm_ty,
243-
Self::FinishFn(me) => &me.ty.norm,
223+
Self::FinishFn(me) | Self::StartFn(me) => &me.ty.norm,
244224
Self::Named(me) => &me.ty.norm,
245225
Self::Skip(me) => &me.norm_ty,
246226
}
247227
}
248228

249229
pub(crate) fn orig_ident(&self) -> &syn::Ident {
250230
match self {
251-
Self::StartFn(me) => &me.base.ident,
252231
Self::Field(me) => &me.ident,
253-
Self::FinishFn(me) => &me.ident,
232+
Self::FinishFn(me) | Self::StartFn(me) => &me.ident,
254233
Self::Named(me) => &me.name.orig,
255234
Self::Skip(me) => &me.ident,
256235
}
@@ -270,7 +249,7 @@ impl Member {
270249
}
271250
}
272251

273-
pub(crate) fn as_start_fn(&self) -> Option<&StartFnMember> {
252+
pub(crate) fn as_start_fn(&self) -> Option<&PosFnMember> {
274253
match self {
275254
Self::StartFn(me) => Some(me),
276255
_ => None,

bon-macros/src/builder/builder_gen/mod.rs

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -15,10 +15,8 @@ pub(crate) use top_level_config::TopLevelConfig;
1515

1616
use crate::util::prelude::*;
1717
use getters::GettersCtx;
18-
use member::{
19-
CustomField, Member, MemberOrigin, NamedMember, PosFnMember, RawMember, StartFnMember,
20-
};
21-
use models::{AssocMethodCtx, AssocMethodReceiverCtx, BuilderGenCtx, FinishFnBody, Generics};
18+
use member::{CustomField, Member, MemberOrigin, NamedMember, PosFnMember, RawMember};
19+
use models::{AssocMethodCtxParams, AssocMethodReceiverCtx, BuilderGenCtx, FinishFnBody, Generics};
2220
use setters::SettersCtx;
2321

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

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

0 commit comments

Comments
 (0)