use std::hash::{BuildHasherDefault, Hasher};
#[derive(Debug, Default)]
pub(crate) struct PointerHasher {
value: u64,
}
impl Hasher for PointerHasher {
#[cfg_attr(test, mutants::skip)] fn finish(&self) -> u64 {
self.value
}
#[cfg_attr(test, mutants::skip)] fn write(&mut self, bytes: &[u8]) {
let input_raw = if let Ok(bytes) = <[u8; 8]>::try_from(bytes) {
u64::from_ne_bytes(bytes)
} else {
u64::from(u32::from_ne_bytes(
bytes
.try_into()
.expect("PointerHasher input must represent a 32-bit or 64-bit pointer"),
))
};
self.value ^= input_raw;
self.value ^= input_raw.reverse_bits();
}
}
pub(crate) type BuildPointerHasher = BuildHasherDefault<PointerHasher>;
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn same_same() {
let mut hasher1 = PointerHasher::default();
let mut hasher2 = PointerHasher::default();
hasher1.write(&1u64.to_ne_bytes());
hasher2.write(&1u64.to_ne_bytes());
assert_eq!(hasher1.finish(), hasher2.finish());
}
#[test]
fn accepts_32_bit_input() {
let mut hasher = PointerHasher::default();
hasher.write(&1u32.to_ne_bytes());
assert_ne!(hasher.finish(), 0);
}
#[test]
#[should_panic(expected = "PointerHasher input must represent a 32-bit or 64-bit pointer")]
fn rejects_other_input_widths() {
PointerHasher::default().write(&[1]);
}
}