educe/trait_handlers/hash/
hash_struct.rs1use quote::quote;
2use syn::{Data, DeriveInput, Meta, Path, Type};
3
4use super::{
5 models::{FieldAttributeBuilder, TypeAttributeBuilder},
6 TraitHandler,
7};
8use crate::{common::ident_index::IdentOrIndex, Trait};
9
10pub(crate) struct HashStructHandler;
11
12impl TraitHandler for HashStructHandler {
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_hash_meta(meta)?;
25
26 let mut hash_types: Vec<&Type> = Vec::new();
27
28 let mut hash_token_stream = proc_macro2::TokenStream::new();
29
30 if let Data::Struct(data) = &ast.data {
31 let built_in_hash: Path = syn::parse2(quote!(::core::hash::Hash::hash)).unwrap();
32
33 for (index, field) in data.fields.iter().enumerate() {
34 let field_attribute = FieldAttributeBuilder {
35 enable_ignore: true,
36 enable_method: true,
37 }
38 .build_from_attributes(&field.attrs, traits)?;
39
40 if field_attribute.ignore {
41 continue;
42 }
43
44 let field_name = if let Some(ident) = field.ident.as_ref() {
45 IdentOrIndex::from(ident)
46 } else {
47 IdentOrIndex::from(index)
48 };
49
50 let hash = field_attribute.method.as_ref().unwrap_or_else(|| {
51 hash_types.push(&field.ty);
52 &built_in_hash
53 });
54
55 hash_token_stream.extend(quote!( #hash(&self.#field_name, state); ));
56 }
57 }
58
59 let ident = &ast.ident;
60
61 let bound = type_attribute.bound.into_where_predicates_by_generic_parameters_check_types(
62 &ast.generics.params,
63 &syn::parse2(quote!(::core::hash::Hash)).unwrap(),
64 &hash_types,
65 &[],
66 );
67
68 let mut generics = ast.generics.clone();
69 let where_clause = generics.make_where_clause();
70
71 for where_predicate in bound {
72 where_clause.predicates.push(where_predicate);
73 }
74
75 let (impl_generics, ty_generics, where_clause) = generics.split_for_impl();
76
77 token_stream.extend(quote! {
78 impl #impl_generics ::core::hash::Hash for #ident #ty_generics #where_clause {
79 #[inline]
80 fn hash<H: ::core::hash::Hasher>(&self, state: &mut H) {
81 #hash_token_stream
82 }
83 }
84 });
85
86 Ok(())
87 }
88}