1 | //! [`Clone`](trait@std::clone::Clone) implementation. |
2 | |
3 | use proc_macro2::TokenStream; |
4 | use quote::quote; |
5 | use syn::{TraitBound, TraitBoundModifier, TypeParamBound}; |
6 | |
7 | use crate::{Data, DataType, DeriveTrait, Item, SimpleType, SplitGenerics, Trait, TraitImpl}; |
8 | |
9 | /// Dummy-struct implement [`Trait`] for [`Clone`](trait@std::clone::Clone). |
10 | pub struct Clone; |
11 | |
12 | impl TraitImpl for Clone { |
13 | fn as_str(&self) -> &'static str { |
14 | "Clone" |
15 | } |
16 | |
17 | fn default_derive_trait(&self) -> DeriveTrait { |
18 | DeriveTrait::Clone |
19 | } |
20 | |
21 | fn supports_union(&self) -> bool { |
22 | true |
23 | } |
24 | |
25 | fn additional_where_bounds(&self, data: &Item) -> Option<TypeParamBound> { |
26 | // `Clone` for unions requires the `Copy` bound. |
27 | if let Item::Item(Data { |
28 | type_: DataType::Union(..), |
29 | .. |
30 | }) = data |
31 | { |
32 | Some(TypeParamBound::Trait(TraitBound { |
33 | paren_token: None, |
34 | modifier: TraitBoundModifier::None, |
35 | lifetimes: None, |
36 | path: Trait::Copy.default_derive_trait().path(), |
37 | })) |
38 | } else { |
39 | None |
40 | } |
41 | } |
42 | |
43 | fn build_signature( |
44 | &self, |
45 | any_bound: bool, |
46 | item: &Item, |
47 | _generics: &SplitGenerics<'_>, |
48 | traits: &[DeriveTrait], |
49 | _trait_: &DeriveTrait, |
50 | body: &TokenStream, |
51 | ) -> TokenStream { |
52 | // Special implementation for items also implementing `Copy`. |
53 | if !any_bound && traits.iter().any(|trait_| trait_ == Trait::Copy) { |
54 | return quote! { |
55 | #[inline] |
56 | fn clone(&self) -> Self { *self } |
57 | }; |
58 | } |
59 | |
60 | // Special implementation for unions. |
61 | if let Item::Item(Data { |
62 | type_: DataType::Union(..), |
63 | .. |
64 | }) = item |
65 | { |
66 | quote! { |
67 | #[inline] |
68 | fn clone(&self) -> Self { |
69 | struct __AssertCopy<__T: ::core::marker::Copy + ?::core::marker::Sized>(::core::marker::PhantomData<__T>); |
70 | let _: __AssertCopy<Self>; |
71 | *self |
72 | } |
73 | } |
74 | } else { |
75 | quote! { |
76 | #[inline] |
77 | fn clone(&self) -> Self { |
78 | match self { |
79 | #body |
80 | } |
81 | } |
82 | } |
83 | } |
84 | } |
85 | |
86 | fn build_body( |
87 | &self, |
88 | any_bound: bool, |
89 | traits: &[DeriveTrait], |
90 | trait_: &DeriveTrait, |
91 | data: &Data, |
92 | ) -> TokenStream { |
93 | if !any_bound && traits.iter().any(|trait_| trait_ == Trait::Copy) { |
94 | return TokenStream::new(); |
95 | } |
96 | |
97 | match data.simple_type() { |
98 | SimpleType::Struct(fields) => { |
99 | let self_pattern = &fields.self_pattern; |
100 | let item_path = &data.path; |
101 | let self_ident = data.iter_self_ident(**trait_); |
102 | let fields = data.iter_field_ident(**trait_); |
103 | let trait_path = trait_.path(); |
104 | |
105 | quote! { |
106 | #self_pattern => #item_path { #(#fields: #trait_path::clone(#self_ident)),* }, |
107 | } |
108 | } |
109 | SimpleType::Tuple(fields) => { |
110 | let self_pattern = &fields.self_pattern; |
111 | let item_path = &data.path; |
112 | let self_ident = data.iter_self_ident(**trait_); |
113 | let trait_path = trait_.path(); |
114 | |
115 | quote! { |
116 | #self_pattern => #item_path(#(#trait_path::clone(#self_ident)),*), |
117 | } |
118 | } |
119 | SimpleType::Unit(pattern) => { |
120 | quote! { #pattern => #pattern, } |
121 | } |
122 | SimpleType::Union(_) => TokenStream::new(), |
123 | } |
124 | } |
125 | } |
126 | |