pub use hmac::digest::Digest; use std::collections::HashSet; /// Deterministically hash a value by feeding its fields into the hasher in a consistent order. #[diagnostic::on_unimplemented( note = "for local types consider adding `#[derive(arbiter_macros::Hashable)]` to your `{Self}` type", note = "for types from other crates check whether the crate offers a `Hashable` implementation" )] pub trait Hashable { fn hash(&self, hasher: &mut H); } macro_rules! impl_numeric { ($($t:ty),*) => { $( impl Hashable for $t { fn hash(&self, hasher: &mut H) { hasher.update(&self.to_be_bytes()); } } )* }; } impl_numeric!(u8, u16, u32, u64, i8, i16, i32, i64); impl Hashable for &[u8] { fn hash(&self, hasher: &mut H) { hasher.update(self); } } impl Hashable for String { fn hash(&self, hasher: &mut H) { hasher.update(self.as_bytes()); } } impl Hashable for Vec { fn hash(&self, hasher: &mut H) { let ref_sorted = { let mut sorted = self.iter().collect::>(); sorted.sort_by(|a, b| a.partial_cmp(b).unwrap()); sorted }; for item in ref_sorted { item.hash(hasher); } } } impl Hashable for HashSet { fn hash(&self, hasher: &mut H) { let ref_sorted = { let mut sorted = self.iter().collect::>(); sorted.sort_by(|a, b| a.partial_cmp(b).unwrap()); sorted }; for item in ref_sorted { item.hash(hasher); } } } impl Hashable for Option { fn hash(&self, hasher: &mut H) { match self { Some(value) => { hasher.update([1]); value.hash(hasher); } None => hasher.update([0]), } } } impl Hashable for Box { fn hash(&self, hasher: &mut H) { self.as_ref().hash(hasher); } } impl Hashable for &T { fn hash(&self, hasher: &mut H) { (*self).hash(hasher); } } impl Hashable for alloy::primitives::Address { fn hash(&self, hasher: &mut H) { hasher.update(self.as_slice()); } } impl Hashable for alloy::primitives::U256 { fn hash(&self, hasher: &mut H) { hasher.update(self.to_be_bytes::<32>()); } } impl Hashable for chrono::Duration { fn hash(&self, hasher: &mut H) { hasher.update(self.num_seconds().to_be_bytes()); } } impl Hashable for chrono::DateTime { fn hash(&self, hasher: &mut H) { hasher.update(self.timestamp_millis().to_be_bytes()); } }