use core::hash::Hash;
#[cfg(debug_assertions)]
use core::hash::Hasher;
#[cfg(debug_assertions)]
struct Fnv(u64);
#[cfg(debug_assertions)]
impl Hasher for Fnv {
fn finish(&self) -> u64 {
self.0
}
fn write(&mut self, bytes: &[u8]) {
for &b in bytes {
self.0 ^= u64::from(b);
self.0 = self.0.wrapping_mul(0x0000_0100_0000_01b3);
}
}
}
#[cfg(debug_assertions)]
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Default)]
pub struct Tag(u32);
#[cfg(not(debug_assertions))]
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Default)]
pub struct Tag;
impl Tag {
#[cfg(debug_assertions)]
pub(crate) fn of<H: Hash>(items: impl IntoIterator<Item = H>) -> Self {
let mut h = Fnv(0xcbf2_9ce4_8422_2325);
let mut n: u64 = 0;
for item in items {
item.hash(&mut h);
n += 1;
}
h.write_u64(n);
#[allow(clippy::cast_possible_truncation)]
Self(h.finish() as u32 | 1)
}
#[cfg(not(debug_assertions))]
pub(crate) fn of<H: Hash>(items: impl IntoIterator<Item = H>) -> Self {
let _ = items;
Self
}
pub(crate) fn agrees(self, other: Self) -> bool {
self == other || self == Self::ANY || other == Self::ANY
}
}
impl Tag {
pub(crate) const ANY: Self = Self::any();
#[cfg(debug_assertions)]
const fn any() -> Self {
Self(0)
}
#[cfg(not(debug_assertions))]
const fn any() -> Self {
Self
}
}