1//! [`Clone`](trait@std::clone::Clone) implementation.
2
3use proc_macro2::TokenStream;
4use quote::quote;
5use syn::{TraitBound, TraitBoundModifier, TypeParamBound};
6
7use crate::{Data, DataType, DeriveTrait, Item, SimpleType, SplitGenerics, Trait, TraitImpl};
8
9/// Dummy-struct implement [`Trait`] for [`Clone`](trait@std::clone::Clone).
10pub struct Clone;
11
12impl 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