educe/trait_handlers/copy/
mod.rs

1mod models;
2
3use models::{FieldAttributeBuilder, TypeAttributeBuilder};
4use quote::quote;
5use syn::{Data, DeriveInput, Meta};
6
7use super::TraitHandler;
8use crate::Trait;
9
10pub(crate) struct CopyHandler;
11
12impl TraitHandler for CopyHandler {
13    #[inline]
14    fn trait_meta_handler(
15        ast: &DeriveInput,
16        token_stream: &mut proc_macro2::TokenStream,
17        traits: &[Trait],
18        meta: &Meta,
19    ) -> syn::Result<()> {
20        #[cfg(feature = "Clone")]
21        let contains_clone = traits.contains(&Trait::Clone);
22
23        #[cfg(not(feature = "Clone"))]
24        let contains_clone = false;
25
26        let type_attribute = TypeAttributeBuilder {
27            enable_flag:  true,
28            enable_bound: !contains_clone,
29        }
30        .build_from_copy_meta(meta)?;
31
32        let mut field_types = vec![];
33
34        // if `contains_clone` is true, the implementation is handled by the `Clone` attribute, and field attributes is also handled by the `Clone` attribute
35        if !contains_clone {
36            match &ast.data {
37                Data::Struct(data) => {
38                    for field in data.fields.iter() {
39                        field_types.push(&field.ty);
40                        let _ =
41                            FieldAttributeBuilder.build_from_attributes(&field.attrs, traits)?;
42                    }
43                },
44                Data::Enum(data) => {
45                    for variant in data.variants.iter() {
46                        let _ = TypeAttributeBuilder {
47                            enable_flag: false, enable_bound: false
48                        }
49                        .build_from_attributes(&variant.attrs, traits)?;
50
51                        for field in variant.fields.iter() {
52                            field_types.push(&field.ty);
53                            let _ = FieldAttributeBuilder
54                                .build_from_attributes(&field.attrs, traits)?;
55                        }
56                    }
57                },
58                Data::Union(data) => {
59                    for field in data.fields.named.iter() {
60                        field_types.push(&field.ty);
61                        let _ =
62                            FieldAttributeBuilder.build_from_attributes(&field.attrs, traits)?;
63                    }
64                },
65            }
66
67            let ident = &ast.ident;
68
69            let bound =
70                type_attribute.bound.into_where_predicates_by_generic_parameters_check_types(
71                    &ast.generics.params,
72                    &syn::parse2(quote!(::core::marker::Copy)).unwrap(),
73                    &field_types,
74                    &[quote! {::core::clone::Clone}],
75                );
76
77            let mut generics = ast.generics.clone();
78            let where_clause = generics.make_where_clause();
79
80            for where_predicate in bound {
81                where_clause.predicates.push(where_predicate);
82            }
83
84            let (impl_generics, ty_generics, where_clause) = generics.split_for_impl();
85
86            token_stream.extend(quote! {
87                impl #impl_generics ::core::marker::Copy for #ident #ty_generics #where_clause {
88                }
89            });
90        }
91
92        Ok(())
93    }
94}