use core::hash::BuildHasher;
#[cfg(feature = "debug")]
use core::fmt::Debug;
#[cfg(feature = "fully_randomised_wyhash")]
use std::sync::LazyLock;
use crate::utils::get_random_u64;
use super::{secret::LegacySecret, WyHashLegacy};
#[cfg(feature = "fully_randomised_wyhash")]
static SECRET: LazyLock<LegacySecret> = LazyLock::new(|| {
use super::secret::make_secret_legacy;
make_secret_legacy(get_random_u64())
});
#[derive(Clone)]
#[cfg_attr(feature = "serde1", derive(serde::Serialize, serde::Deserialize))]
pub struct RandomWyHashLegacyState {
state: u64,
secret: LegacySecret,
}
impl RandomWyHashLegacyState {
#[must_use]
#[inline]
pub fn new() -> Self {
#[cfg(not(feature = "fully_randomised_wyhash"))]
use super::constants::{WY0, WY1, WY2, WY3};
#[cfg(feature = "fully_randomised_wyhash")]
let secret = SECRET.clone();
#[cfg(not(feature = "fully_randomised_wyhash"))]
let secret = LegacySecret::new(WY0, WY1, WY2, WY3);
Self::new_with_secret(secret)
}
#[must_use]
#[inline]
pub fn new_with_secret(secret: LegacySecret) -> Self {
Self {
state: get_random_u64(),
secret,
}
}
}
impl BuildHasher for RandomWyHashLegacyState {
type Hasher = WyHashLegacy;
#[inline]
fn build_hasher(&self) -> Self::Hasher {
WyHashLegacy::new_with_secret(self.state, self.secret.clone())
}
}
impl Default for RandomWyHashLegacyState {
#[inline]
fn default() -> Self {
Self::new()
}
}
#[cfg(feature = "debug")]
impl Debug for RandomWyHashLegacyState {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
f.debug_struct("RandomisedWyHashLegacyState")
.finish_non_exhaustive()
}
}
#[cfg(test)]
mod tests {
extern crate alloc;
use super::*;
#[cfg(feature = "debug")]
#[test]
fn no_leaking_debug() {
use alloc::format;
let builder = RandomWyHashLegacyState::default();
assert_eq!(
format!("{builder:?}"),
"RandomisedWyHashLegacyState { .. }",
"Debug should not be leaking internal state"
);
}
#[test]
fn randomised_builder_states() {
let builder1 = RandomWyHashLegacyState::new();
let builder2 = RandomWyHashLegacyState::new();
assert_ne!(&builder1.state, &builder2.state);
assert_eq!(&builder1.secret, &builder2.secret);
#[cfg(feature = "fully_randomised_wyhash")]
{
use super::super::constants::{WY0, WY1, WY2, WY3};
let default_secret = LegacySecret::new(WY0, WY1, WY2, WY3);
assert_ne!(&builder1.secret, &default_secret);
assert_ne!(&builder2.secret, &default_secret);
}
}
}