ass_core/utils/hashers.rs
1//! Hash function utilities for consistent performance across platforms
2//!
3//! Provides ahash-based hashers optimized for ASS-RS use cases with `DoS` resistance
4//! and consistent performance across platforms including WASM.
5//!
6//! # Features
7//!
8//! - DoS-resistant hashing via ahash with random seeds
9//! - WASM-compatible implementation
10//! - `no_std` support when needed
11//! - Deterministic hashing for testing when enabled
12
13use ahash::{AHasher, RandomState};
14use core::hash::{BuildHasher, Hasher};
15
16#[cfg(not(feature = "std"))]
17extern crate alloc;
18#[cfg(not(feature = "std"))]
19use hashbrown::HashMap;
20#[cfg(feature = "std")]
21use std::collections::HashMap;
22/// Create a new `HashMap` with optimized hasher for ASS-RS use cases
23///
24/// Uses ahash for consistent performance across platforms with `DoS` resistance.
25/// Automatically handles `no_std` vs std `HashMap` selection.
26///
27/// # Example
28///
29/// ```rust
30/// use ass_core::utils::hashers::create_hash_map;
31///
32/// let mut map = create_hash_map::<String, i32>();
33/// map.insert("key".to_string(), 42);
34/// ```
35#[must_use]
36pub fn create_hash_map<K, V>() -> HashMap<K, V, RandomState> {
37 HashMap::with_hasher(RandomState::new())
38}
39
40/// Create a new `HashMap` with specific capacity and optimized hasher
41///
42/// Pre-allocates the specified capacity to avoid rehashing during construction.
43/// Useful when the approximate size is known in advance.
44///
45/// # Example
46///
47/// ```rust
48/// use ass_core::utils::hashers::create_hash_map_with_capacity;
49///
50/// // Pre-allocate for expected 100 entries
51/// let mut map = create_hash_map_with_capacity::<String, i32>(100);
52/// ```
53#[must_use]
54pub fn create_hash_map_with_capacity<K, V>(capacity: usize) -> HashMap<K, V, RandomState> {
55 HashMap::with_capacity_and_hasher(capacity, RandomState::new())
56}
57
58/// Create a hasher instance for manual hashing operations
59///
60/// Returns an ahash hasher with random seed for `DoS` resistance.
61/// Use this when you need to hash individual values outside of `HashMap`.
62///
63/// # Example
64///
65/// ```rust
66/// use std::hash::{Hash, Hasher};
67/// use ass_core::utils::create_hasher;
68///
69/// let mut hasher = create_hasher();
70/// "some string".hash(&mut hasher);
71/// let hash_value = hasher.finish();
72/// ```
73#[must_use]
74pub fn create_hasher() -> AHasher {
75 RandomState::new().build_hasher()
76}
77
78/// Create a deterministic hasher for testing purposes
79///
80/// Uses a fixed seed to ensure reproducible hash values across test runs.
81/// Should only be used in testing scenarios.
82///
83/// # Example
84///
85/// ```rust
86/// use std::hash::Hash;
87/// use ass_core::utils::create_deterministic_hasher;
88///
89/// #[cfg(test)]
90/// let mut hasher = create_deterministic_hasher();
91/// ```
92#[cfg(test)]
93#[must_use]
94pub fn create_deterministic_hasher() -> AHasher {
95 use ahash::RandomState;
96 RandomState::with_seeds(0x1234_5678_9abc_def0, 0xfedc_ba98_7654_3210, 0, 0).build_hasher()
97}
98
99/// Hash a single value using the optimized hasher
100///
101/// Convenience function for hashing individual values with the same
102/// hasher configuration used throughout ASS-RS.
103///
104/// # Example
105///
106/// ```rust
107/// use ass_core::utils::hashers::hash_value;
108///
109/// let hash = hash_value(&"test string");
110/// let hash2 = hash_value(&42u32);
111/// ```
112pub fn hash_value<T: core::hash::Hash>(value: &T) -> u64 {
113 let mut hasher = create_hasher();
114 value.hash(&mut hasher);
115 hasher.finish()
116}
117
118/// Configuration for hash-related performance tuning
119#[derive(Debug, Clone)]
120pub struct HashConfig {
121 /// Whether to use deterministic hashing (testing only)
122 pub deterministic: bool,
123
124 /// Initial capacity hint for `HashMaps`
125 pub default_capacity: usize,
126
127 /// Load factor before rehashing (0.0 to 1.0)
128 pub load_factor: f32,
129}
130
131impl Default for HashConfig {
132 fn default() -> Self {
133 Self {
134 deterministic: false,
135 default_capacity: 16,
136 load_factor: 0.75,
137 }
138 }
139}
140
141impl HashConfig {
142 /// Create configuration for testing with deterministic behavior
143 #[cfg(test)]
144 #[must_use]
145 pub const fn for_testing() -> Self {
146 Self {
147 deterministic: true,
148 default_capacity: 8,
149 load_factor: 0.75,
150 }
151 }
152
153 /// Create `HashMap` using this configuration
154 #[must_use]
155 pub fn create_map<K, V>(&self) -> HashMap<K, V, RandomState> {
156 if self.deterministic {
157 HashMap::with_capacity_and_hasher(
158 self.default_capacity,
159 RandomState::with_seeds(0x1234_5678_9abc_def0, 0xfedc_ba98_7654_3210, 0, 0),
160 )
161 } else {
162 create_hash_map_with_capacity(self.default_capacity)
163 }
164 }
165}
166
167#[cfg(test)]
168mod tests {}