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
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
use super::BuilderGenCtx;
use crate::builder::builder_gen::top_level_config::DeriveConfig;
use crate::util::prelude::*;
impl BuilderGenCtx {
pub(super) fn derive_clone(&self, derive: &DeriveConfig) -> TokenStream {
let bon = &self.bon;
let generics_decl = &self.generics.decl_without_defaults;
let generic_args = &self.generics.args;
let builder_ident = &self.builder_type.ident;
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! {
#ident: <#ty as #clone>::clone(&self.#ident),
}
});
let clone_start_fn_args = self.start_fn_args().map(|member| {
let member_ident = &member.ident;
let member_ty = &member.ty.norm;
quote! {
// 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)
}
});
let where_clause = self.where_clause_for_derive(&clone, derive);
let state_mod = &self.state_mod.ident;
let clone_named_members = self.named_members().map(|member| {
let member_index = &member.index;
// 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.
let ty = member.underlying_norm_ty();
quote! {
#bon::__::better_errors::clone_member::<#ty>(
&self.__unsafe_private_named.#member_index
)
}
});
let clone_fields = self.custom_fields().map(|member| {
let member_ident = &member.ident;
let member_ty = &member.norm_ty;
quote! {
// 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)
}
});
let state_var = &self.state_var;
quote! {
#[automatically_derived]
impl<
#(#generics_decl,)*
#state_var: #state_mod::State
>
#clone for #builder_ident<
#(#generic_args,)*
#state_var
>
#where_clause
{
fn clone(&self) -> Self {
Self {
__unsafe_private_phantom: ::core::marker::PhantomData,
#clone_receiver
#( #clone_start_fn_args, )*
#( #clone_fields, )*
// 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_named: ( #( #clone_named_members, )* ),
}
}
}
}
}
}