const GAMMA: u64 = 0x9E37_79B9_7F4A_7C15;
const MIX1: u64 = 0xBF58_476D_1CE4_E5B9;
const MIX2: u64 = 0x94D0_49BB_1331_11EB;
#[inline]
#[must_use]
pub fn finalize(seed: u64) -> u64 {
let mut z = seed.wrapping_add(GAMMA);
z = (z ^ (z >> 30)).wrapping_mul(MIX1);
z = (z ^ (z >> 27)).wrapping_mul(MIX2);
z ^ (z >> 31)
}
#[inline]
#[must_use]
pub fn pair(a: u8, b: u8) -> u64 {
finalize((u64::from(a) << 8) | u64::from(b))
}
#[cfg(test)]
mod tests {
use super::{finalize, pair};
fn differing_bits(a: u64, b: u64) -> u32 {
(a ^ b).count_ones()
}
#[test]
fn zero_seed_matches_reference() {
assert_eq!(finalize(0), 0xE220_A839_7B1D_CDAF);
}
#[test]
fn pair_maps_to_seed_finalization() {
assert_eq!(pair(b'a', b'b'), finalize(0x6162));
}
#[test]
fn finalize_has_strong_single_bit_avalanche() {
let base = finalize(0x0123_4567_89AB_CDEF);
let flipped = finalize(0x0123_4567_89AB_CDEE);
assert!(differing_bits(base, flipped) >= 24);
}
#[test]
fn finalize_has_strong_high_bit_avalanche() {
let base = finalize(0x0123_4567_89AB_CDEF);
let flipped = finalize(0x8123_4567_89AB_CDEF);
assert!(differing_bits(base, flipped) >= 24);
}
#[test]
fn pair_distinguishes_order() {
assert_ne!(pair(b'a', b'b'), pair(b'b', b'a'));
}
}