use std::fmt;
use std::hash::Hasher;
const FNV1A64_OFFSET_BASIS: u64 = 0xcbf2_9ce4_8422_2325;
const FNV1A64_PRIME: u64 = 0x0000_0100_0000_01b3;
#[derive(Clone, Copy, PartialEq, Eq, Hash, Default)]
pub struct Fingerprint(u64);
impl Fingerprint {
pub(super) const fn from_hash(hash: u64) -> Self {
Self(hash)
}
#[must_use]
pub fn of(bytes: &[u8]) -> Self {
let mut hasher = Fnv1a::new();
hasher.write(bytes);
Self(hasher.finish())
}
#[must_use]
pub const fn get(self) -> u64 {
self.0
}
}
impl fmt::Display for Fingerprint {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "fnv1a64:{:016x}", self.0)
}
}
impl fmt::Debug for Fingerprint {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "{self}")
}
}
pub(super) struct Fnv1a(u64);
impl Fnv1a {
pub(super) const fn new() -> Self {
Self(FNV1A64_OFFSET_BASIS)
}
}
impl Hasher for Fnv1a {
fn finish(&self) -> u64 {
self.0
}
fn write(&mut self, bytes: &[u8]) {
for byte in bytes {
self.0 ^= u64::from(*byte);
self.0 = self.0.wrapping_mul(FNV1A64_PRIME);
}
}
}