bon_macros/builder/builder_gen/builder_derives/
clone.rs

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