| 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 | |