From 5be0a31b959c18af57e811e937e99e4f7fb0a3cc Mon Sep 17 00:00:00 2001 From: DaniPopes <57450786+DaniPopes@users.noreply.github.com> Date: Wed, 25 Sep 2024 19:46:59 +0200 Subject: [PATCH] fix(primitives): make sure DefaultHashBuilder implements Clone (#748) --- crates/primitives/src/map/fixed.rs | 10 ++++-- crates/primitives/src/map/mod.rs | 51 +++++++++++++++++++++++++++++- 2 files changed, 58 insertions(+), 3 deletions(-) diff --git a/crates/primitives/src/map/fixed.rs b/crates/primitives/src/map/fixed.rs index f59a86cf3..ed15067f2 100644 --- a/crates/primitives/src/map/fixed.rs +++ b/crates/primitives/src/map/fixed.rs @@ -72,7 +72,7 @@ macro_rules! assert_eq_unchecked { /// Works best with `fxhash`, enabled by default with the "map-fxhash" feature. /// /// **NOTE:** this hasher accepts only `N`-length byte arrays! It is invalid to hash anything else. -#[derive(Default)] +#[derive(Clone, Default)] pub struct FbBuildHasher { inner: DefaultHashBuilder, _marker: core::marker::PhantomData<[(); N]>, @@ -98,7 +98,7 @@ impl BuildHasher for FbBuildHasher { /// Works best with `fxhash`, enabled by default with the "map-fxhash" feature. /// /// **NOTE:** this hasher accepts only `N`-length byte arrays! It is invalid to hash anything else. -#[derive(Default)] +#[derive(Clone, Default)] pub struct FbHasher { inner: DefaultHasher, _marker: core::marker::PhantomData<[(); N]>, @@ -201,5 +201,11 @@ mod tests { map.insert(Address::ZERO, true); assert_eq!(map.get(&Address::ZERO), Some(&true)); assert_eq!(map.get(&Address::with_last_byte(1)), None); + + let map2 = map.clone(); + assert_eq!(map.len(), map2.len()); + assert_eq!(map.len(), 1); + assert_eq!(map2.get(&Address::ZERO), Some(&true)); + assert_eq!(map2.get(&Address::with_last_byte(1)), None); } } diff --git a/crates/primitives/src/map/mod.rs b/crates/primitives/src/map/mod.rs index 7cdb5a786..57949d9a6 100644 --- a/crates/primitives/src/map/mod.rs +++ b/crates/primitives/src/map/mod.rs @@ -63,7 +63,40 @@ cfg_if! { cfg_if! { if #[cfg(all(feature = "std", feature = "rand"))] { - use rustc_hash::FxRandomState as FxBuildHasherInner; + // use rustc_hash::FxRandomState as FxBuildHasherInner; + + // TODO: Polyfill for https://github.com/rust-lang/rustc-hash/pull/52/ + #[allow(missing_debug_implementations, missing_copy_implementations)] + #[doc(hidden)] + #[derive(Clone)] + pub struct FxBuildHasherInner(usize); + + impl Default for FxBuildHasherInner { + // Copied from `FxRandomState::new`. + fn default() -> Self { + use rand::Rng; + use std::{cell::Cell, thread_local}; + + thread_local!(static SEED: Cell = { + Cell::new(rand::thread_rng().gen()) + }); + + SEED.with(|seed| { + let s = seed.get(); + seed.set(s.wrapping_add(1)); + Self(s) + }) + } + } + + impl core::hash::BuildHasher for FxBuildHasherInner { + type Hasher = rustc_hash::FxHasher; + + #[inline] + fn build_hasher(&self) -> Self::Hasher { + rustc_hash::FxHasher::with_seed(self.0) + } + } } else { use rustc_hash::FxBuildHasher as FxBuildHasherInner; } @@ -127,3 +160,19 @@ cfg_if! { } } } + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn default_hasher_builder_traits() { + let hash_builder = ::default(); + let _hash_builder2 = ::clone(&hash_builder); + let mut hasher = + ::build_hasher(&hash_builder); + + ::write_u8(&mut hasher, 0); + let _hasher2 = ::clone(&hasher); + } +}