educe/trait_handlers/partial_eq/
partial_eq_struct.rs1use quote::quote;
2use syn::{Data, DeriveInput, Meta, Type};
3
4use super::{
5 models::{FieldAttributeBuilder, TypeAttributeBuilder},
6 TraitHandler,
7};
8use crate::{common::ident_index::IdentOrIndex, Trait};
9
10pub(crate) struct PartialEqStructHandler;
11
12impl TraitHandler for PartialEqStructHandler {
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 let type_attribute =
21 TypeAttributeBuilder {
22 enable_flag: true, enable_unsafe: false, enable_bound: true
23 }
24 .build_from_partial_eq_meta(meta)?;
25
26 let mut partial_eq_types: Vec<&Type> = Vec::new();
27
28 let mut eq_token_stream = proc_macro2::TokenStream::new();
29
30 if let Data::Struct(data) = &ast.data {
31 for (index, field) in data.fields.iter().enumerate() {
32 let field_attribute = FieldAttributeBuilder {
33 enable_ignore: true,
34 enable_method: true,
35 }
36 .build_from_attributes(&field.attrs, traits)?;
37
38 if field_attribute.ignore {
39 continue;
40 }
41
42 let field_name = IdentOrIndex::from_ident_with_index(field.ident.as_ref(), index);
43
44 if let Some(method) = field_attribute.method {
45 eq_token_stream.extend(quote! {
46 if !#method(&self.#field_name, &other.#field_name) {
47 return false;
48 }
49 });
50 } else {
51 let ty = &field.ty;
52
53 partial_eq_types.push(ty);
54
55 eq_token_stream.extend(quote! {
56 if ::core::cmp::PartialEq::ne(&self.#field_name, &other.#field_name) {
57 return false;
58 }
59 });
60 }
61 }
62 }
63
64 let ident = &ast.ident;
65
66 let bound = type_attribute.bound.into_where_predicates_by_generic_parameters_check_types(
67 &ast.generics.params,
68 &syn::parse2(quote!(::core::cmp::PartialEq)).unwrap(),
69 &partial_eq_types,
70 &[],
71 );
72
73 let mut generics = ast.generics.clone();
74 let where_clause = generics.make_where_clause();
75
76 for where_predicate in bound {
77 where_clause.predicates.push(where_predicate);
78 }
79
80 let (impl_generics, ty_generics, where_clause) = generics.split_for_impl();
81
82 token_stream.extend(quote! {
83 impl #impl_generics ::core::cmp::PartialEq for #ident #ty_generics #where_clause {
84 #[inline]
85 fn eq(&self, other: &Self) -> bool {
86 #eq_token_stream
87
88 true
89 }
90 }
91 });
92
93 #[cfg(feature = "Eq")]
94 if traits.contains(&Trait::Eq) {
95 token_stream.extend(quote! {
96 impl #impl_generics ::core::cmp::Eq for #ident #ty_generics #where_clause {
97 }
98 });
99 }
100
101 Ok(())
102 }
103}