educe/trait_handlers/hash/
hash_struct.rs1use std::str::FromStr;
2
3use proc_macro2::TokenStream;
4use quote::quote;
5use syn::{Data, DeriveInput, Generics, Meta};
6
7use super::{
8 super::TraitHandler,
9 models::{FieldAttributeBuilder, TypeAttributeBuilder},
10};
11use crate::Trait;
12
13pub struct HashStructHandler;
14
15impl TraitHandler for HashStructHandler {
16 fn trait_meta_handler(
17 ast: &DeriveInput,
18 tokens: &mut TokenStream,
19 traits: &[Trait],
20 meta: &Meta,
21 ) {
22 let type_attribute = TypeAttributeBuilder {
23 enable_flag: true, enable_bound: true
24 }
25 .from_hash_meta(meta);
26
27 let bound = type_attribute
28 .bound
29 .into_punctuated_where_predicates_by_generic_parameters(&ast.generics.params);
30
31 let mut hasher_tokens = TokenStream::new();
32
33 if let Data::Struct(data) = &ast.data {
34 for (index, field) in data.fields.iter().enumerate() {
35 let field_attribute = FieldAttributeBuilder {
36 enable_ignore: true,
37 enable_impl: true,
38 }
39 .from_attributes(&field.attrs, traits);
40
41 if field_attribute.ignore {
42 continue;
43 }
44
45 let hash_trait = field_attribute.hash_trait;
46 let hash_method = field_attribute.hash_method;
47
48 let field_name = if let Some(ident) = field.ident.as_ref() {
49 ident.to_string()
50 } else {
51 format!("{}", index)
52 };
53
54 match hash_trait {
55 Some(hash_trait) => {
56 let hash_method = hash_method.unwrap();
57
58 let statement = format!(
59 "{hash_trait}::{hash_method}(&self.{field_name}, state);",
60 hash_trait = hash_trait,
61 hash_method = hash_method,
62 field_name = field_name
63 );
64
65 hasher_tokens.extend(TokenStream::from_str(&statement).unwrap());
66 },
67 None => match hash_method {
68 Some(hash_method) => {
69 let statement = format!(
70 "{hash_method}(&self.{field_name}, state);",
71 hash_method = hash_method,
72 field_name = field_name
73 );
74
75 hasher_tokens.extend(TokenStream::from_str(&statement).unwrap());
76 },
77 None => {
78 let statement = format!(
79 "core::hash::Hash::hash(&self.{field_name}, state);",
80 field_name = field_name
81 );
82
83 hasher_tokens.extend(TokenStream::from_str(&statement).unwrap());
84 },
85 },
86 }
87 }
88 }
89
90 let ident = &ast.ident;
91
92 let mut generics_cloned: Generics = ast.generics.clone();
93
94 let where_clause = generics_cloned.make_where_clause();
95
96 for where_predicate in bound {
97 where_clause.predicates.push(where_predicate);
98 }
99
100 let (impl_generics, ty_generics, where_clause) = generics_cloned.split_for_impl();
101
102 let hash_impl = quote! {
103 impl #impl_generics core::hash::Hash for #ident #ty_generics #where_clause {
104 #[inline]
105 fn hash<H: core::hash::Hasher>(&self, state: &mut H) {
106 #hasher_tokens
107 }
108 }
109 };
110
111 tokens.extend(hash_impl);
112 }
113}