Skip to content

Commit 50d9c08

Browse files
authored
Introduce #[builder(derive(Into))] attribute (#248)
Closes #247
1 parent 15d06e9 commit 50d9c08

File tree

26 files changed

+714
-358
lines changed

26 files changed

+714
-358
lines changed

.github/workflows/ci.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -243,7 +243,7 @@ jobs:
243243
runs-on: ubuntu-latest
244244
steps:
245245
- uses: actions/checkout@v4
246-
- uses: crate-ci/typos@v1.28.1
246+
- uses: crate-ci/typos@v1.30.1
247247

248248
website-build:
249249
runs-on: ubuntu-latest

bon-macros/src/bon.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ pub(crate) fn generate(params: TokenStream, item: TokenStream) -> TokenStream {
1010
}
1111

1212
pub(crate) fn try_generate(params: TokenStream, item: TokenStream) -> Result<TokenStream> {
13-
let item: syn::Item = syn::parse2(item)?;
13+
let item = syn::parse2(item)?;
1414

1515
let ctx = ExpandCfg {
1616
current_macro: format_ident!("bon"),
@@ -26,7 +26,7 @@ pub(crate) fn try_generate(params: TokenStream, item: TokenStream) -> Result<Tok
2626
let params = NestedMeta::parse_meta_list(input.config)?;
2727
let params = FromMeta::from_list(&params)?;
2828

29-
match input.item {
29+
match *input.item {
3030
syn::Item::Impl(item_impl) => builder::item_impl::generate(params, item_impl),
3131
_ => bail!(
3232
&input.item,

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

Lines changed: 0 additions & 261 deletions
This file was deleted.
Lines changed: 103 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,103 @@
1+
use super::BuilderGenCtx;
2+
use crate::builder::builder_gen::top_level_config::DeriveConfig;
3+
use crate::util::prelude::*;
4+
5+
impl BuilderGenCtx {
6+
pub(super) fn derive_clone(&self, derive: &DeriveConfig) -> TokenStream {
7+
let bon = &self.bon;
8+
let generics_decl = &self.generics.decl_without_defaults;
9+
let generic_args = &self.generics.args;
10+
let builder_ident = &self.builder_type.ident;
11+
12+
let clone = quote!(::core::clone::Clone);
13+
14+
let clone_receiver = self.receiver().map(|receiver| {
15+
let ty = &receiver.without_self_keyword;
16+
quote! {
17+
__unsafe_private_receiver: <#ty as #clone>::clone(&self.__unsafe_private_receiver),
18+
}
19+
});
20+
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);
24+
25+
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+
),
36+
}
37+
});
38+
39+
let where_clause = self.where_clause_for_derive(&clone, derive);
40+
let state_mod = &self.state_mod.ident;
41+
42+
let clone_named_members = self.named_members().map(|member| {
43+
let member_index = &member.index;
44+
45+
// The type hint here is necessary to get better error messages
46+
// that point directly to the type that doesn't implement `Clone`
47+
// in the input code using the span info from the type hint.
48+
let ty = member.underlying_norm_ty();
49+
50+
quote! {
51+
#bon::__::better_errors::clone_member::<#ty>(
52+
&self.__unsafe_private_named.#member_index
53+
)
54+
}
55+
});
56+
57+
let clone_fields = self.custom_fields().map(|member| {
58+
let member_ident = &member.ident;
59+
let member_ty = &member.norm_ty;
60+
61+
quote! {
62+
// The type hint here is necessary to get better error messages
63+
// that point directly to the type that doesn't implement `Clone`
64+
// in the input code using the span info from the type hint.
65+
#member_ident: <#member_ty as #clone>::clone(&self.#member_ident)
66+
}
67+
});
68+
69+
let state_var = &self.state_var;
70+
71+
quote! {
72+
#[automatically_derived]
73+
impl<
74+
#(#generics_decl,)*
75+
#state_var: #state_mod::State
76+
>
77+
#clone for #builder_ident<
78+
#(#generic_args,)*
79+
#state_var
80+
>
81+
#where_clause
82+
{
83+
fn clone(&self) -> Self {
84+
Self {
85+
__unsafe_private_phantom: ::core::marker::PhantomData,
86+
#clone_receiver
87+
#clone_start_fn_args
88+
#( #clone_fields, )*
89+
90+
// We clone named members individually instead of cloning
91+
// the entire tuple to improve error messages in case if
92+
// one of the members doesn't implement `Clone`. This avoids
93+
// a sentence that say smth like
94+
// ```
95+
// required for `(...big type...)` to implement `Clone`
96+
// ```
97+
__unsafe_private_named: ( #( #clone_named_members, )* ),
98+
}
99+
}
100+
}
101+
}
102+
}
103+
}

0 commit comments

Comments
 (0)