rc_hashmap/
hash.rs

1//! Feature-selected default BuildHasher and seeded builders.
2
3#[cfg(any(feature = "wyhash-hash", feature = "xxh3-hash"))]
4use core::hash::BuildHasher;
5
6// Enforce mutual exclusivity of default-hash features at compile time.
7#[cfg(all(
8    feature = "random-state-hash",
9    any(feature = "wyhash-hash", feature = "xxh3-hash")
10))]
11compile_error!(
12    "Features 'random-state-hash' and ('wyhash-hash' or 'xxh3-hash') are mutually exclusive"
13);
14#[cfg(all(feature = "wyhash-hash", feature = "xxh3-hash"))]
15compile_error!("Features 'wyhash-hash' and 'xxh3-hash' are mutually exclusive");
16#[cfg(all(
17    not(feature = "random-state-hash"),
18    not(feature = "wyhash-hash"),
19    not(feature = "xxh3-hash")
20))]
21compile_error!(
22    "No default hash feature selected. Enable exactly one of: 'wyhash-hash' (default), 'random-state-hash', or 'xxh3-hash'"
23);
24
25// Default selection type alias
26#[cfg(feature = "random-state-hash")]
27pub type DefaultHashBuilder = std::collections::hash_map::RandomState;
28
29#[cfg(feature = "wyhash-hash")]
30pub type DefaultHashBuilder = WyHashRandomState;
31
32#[cfg(feature = "xxh3-hash")]
33pub type DefaultHashBuilder = Xxh3RandomState;
34
35// Human-readable feature-selected hasher name for benchmarks/diagnostics
36#[cfg(feature = "wyhash-hash")]
37pub const HASH_NAME: &str = "wyhash-hash";
38#[cfg(feature = "random-state-hash")]
39pub const HASH_NAME: &str = "random-state-hash";
40#[cfg(feature = "xxh3-hash")]
41pub const HASH_NAME: &str = "xxh3-hash";
42
43// Seed source, compiled only when a custom seeded builder is selected.
44#[cfg(any(feature = "wyhash-hash", feature = "xxh3-hash"))]
45mod seed {
46    use std::cell::Cell;
47    use std::time::{SystemTime, UNIX_EPOCH};
48
49    thread_local! {
50        static KEY: Cell<u64> = Cell::new(init_key());
51    }
52
53    fn init_key() -> u64 {
54        let mut buf = [0u8; 8];
55        if getrandom::getrandom(&mut buf).is_ok() {
56            u64::from_le_bytes(buf)
57        } else {
58            // Fallback: fold time-based entropy into a single 64-bit value
59            let now = SystemTime::now()
60                .duration_since(UNIX_EPOCH)
61                .unwrap_or_default();
62            let t: u128 = now.as_nanos();
63            let lo = t as u64;
64            let hi = (t >> 64) as u64;
65            let mut k = lo ^ hi.rotate_left(29) ^ 0x9e37_79b9_7f4a_7c15u64;
66            // One extra mix step to decorrelate low-entropy inputs
67            k ^= k.wrapping_mul(0x9e37_79b9_7f4a_7c15u64);
68            k
69        }
70    }
71
72    #[inline]
73    pub fn next_seed() -> u64 {
74        KEY.with(|key| {
75            let k = key.get();
76            key.set(k.wrapping_add(1));
77            k
78        })
79    }
80}
81
82// WyHash seeded builder wrapper
83#[cfg(feature = "wyhash-hash")]
84#[derive(Clone)]
85pub struct WyHashRandomState {
86    builder: wyhash::v1::WyHasherBuilder,
87}
88
89#[cfg(feature = "wyhash-hash")]
90impl Default for WyHashRandomState {
91    fn default() -> Self {
92        let seed = seed::next_seed();
93        Self {
94            builder: wyhash::v1::WyHasherBuilder::new(seed),
95        }
96    }
97}
98
99#[cfg(feature = "wyhash-hash")]
100impl BuildHasher for WyHashRandomState {
101    type Hasher = <wyhash::v1::WyHasherBuilder as BuildHasher>::Hasher;
102    #[inline]
103    fn build_hasher(&self) -> Self::Hasher {
104        self.builder.build_hasher()
105    }
106}
107
108// XXH3 seeded builder wrapper
109#[cfg(feature = "xxh3-hash")]
110#[derive(Clone)]
111pub struct Xxh3RandomState {
112    builder: xxhash_rust::xxh3::Xxh3Builder,
113}
114
115#[cfg(feature = "xxh3-hash")]
116impl Default for Xxh3RandomState {
117    fn default() -> Self {
118        let seed = seed::next_seed();
119        let builder = xxhash_rust::xxh3::Xxh3Builder::new().with_seed(seed);
120        Self { builder }
121    }
122}
123
124#[cfg(feature = "xxh3-hash")]
125impl BuildHasher for Xxh3RandomState {
126    type Hasher = <xxhash_rust::xxh3::Xxh3Builder as BuildHasher>::Hasher;
127    #[inline]
128    fn build_hasher(&self) -> Self::Hasher {
129        self.builder.build_hasher()
130    }
131}