use std::collections::{BTreeMap, BTreeSet, HashMap, HashSet};
const OFFSET_BASIS: u64 = 0xcbf2_9ce4_8422_2325;
const PRIME: u64 = 0x0000_0100_0000_01b3;
#[derive(Clone, Debug)]
pub struct Hasher {
state: u64,
}
impl Hasher {
pub fn new() -> Self {
Hasher {
state: OFFSET_BASIS,
}
}
pub fn write(&mut self, bytes: &[u8]) {
for byte in bytes {
self.state ^= u64::from(*byte);
self.state = self.state.wrapping_mul(PRIME);
}
}
pub fn write_u64(&mut self, value: u64) {
self.write(&value.to_le_bytes());
}
pub fn finish(&self) -> u64 {
self.state
}
}
impl Default for Hasher {
fn default() -> Self {
Hasher::new()
}
}
pub trait Fingerprint {
fn fingerprint(&self, hasher: &mut Hasher);
}
pub fn fingerprint_of<T: Fingerprint + ?Sized>(value: &T) -> u64 {
let mut hasher = Hasher::new();
value.fingerprint(&mut hasher);
hasher.finish()
}
macro_rules! fingerprint_le_bytes {
($($ty:ty),* $(,)?) => {
$(
impl Fingerprint for $ty {
fn fingerprint(&self, hasher: &mut Hasher) {
hasher.write(&self.to_le_bytes());
}
}
)*
};
}
fingerprint_le_bytes!(u8, u16, u32, u64, u128, i8, i16, i32, i64, i128);
macro_rules! fingerprint_widened {
($($ty:ty => $wide:ty),* $(,)?) => {
$(
impl Fingerprint for $ty {
fn fingerprint(&self, hasher: &mut Hasher) {
<$wide as Fingerprint>::fingerprint(&(*self as $wide), hasher);
}
}
)*
};
}
fingerprint_widened!(usize => u64, isize => i64);
impl Fingerprint for bool {
fn fingerprint(&self, hasher: &mut Hasher) {
hasher.write(&[u8::from(*self)]);
}
}
impl Fingerprint for char {
fn fingerprint(&self, hasher: &mut Hasher) {
u32::from(*self).fingerprint(hasher);
}
}
impl Fingerprint for f32 {
fn fingerprint(&self, hasher: &mut Hasher) {
self.to_bits().fingerprint(hasher);
}
}
impl Fingerprint for f64 {
fn fingerprint(&self, hasher: &mut Hasher) {
self.to_bits().fingerprint(hasher);
}
}
impl Fingerprint for str {
fn fingerprint(&self, hasher: &mut Hasher) {
hasher.write_u64(self.len() as u64);
hasher.write(self.as_bytes());
}
}
impl Fingerprint for String {
fn fingerprint(&self, hasher: &mut Hasher) {
self.as_str().fingerprint(hasher);
}
}
impl<T: Fingerprint + ?Sized> Fingerprint for &T {
fn fingerprint(&self, hasher: &mut Hasher) {
(**self).fingerprint(hasher);
}
}
impl<T: Fingerprint + ?Sized> Fingerprint for Box<T> {
fn fingerprint(&self, hasher: &mut Hasher) {
(**self).fingerprint(hasher);
}
}
impl<T: Fingerprint> Fingerprint for Option<T> {
fn fingerprint(&self, hasher: &mut Hasher) {
match self {
None => hasher.write(&[0]),
Some(value) => {
hasher.write(&[1]);
value.fingerprint(hasher);
}
}
}
}
impl<T: Fingerprint, E: Fingerprint> Fingerprint for Result<T, E> {
fn fingerprint(&self, hasher: &mut Hasher) {
match self {
Ok(value) => {
hasher.write(&[0]);
value.fingerprint(hasher);
}
Err(error) => {
hasher.write(&[1]);
error.fingerprint(hasher);
}
}
}
}
impl<T: Fingerprint> Fingerprint for [T] {
fn fingerprint(&self, hasher: &mut Hasher) {
hasher.write_u64(self.len() as u64);
for item in self {
item.fingerprint(hasher);
}
}
}
impl<T: Fingerprint> Fingerprint for Vec<T> {
fn fingerprint(&self, hasher: &mut Hasher) {
self.as_slice().fingerprint(hasher);
}
}
impl Fingerprint for () {
fn fingerprint(&self, _hasher: &mut Hasher) {}
}
macro_rules! fingerprint_tuples {
($(($($index:tt $param:ident),+))+) => {
$(
impl<$($param: Fingerprint),+> Fingerprint for ($($param,)+) {
fn fingerprint(&self, hasher: &mut Hasher) {
$(self.$index.fingerprint(hasher);)+
}
}
)+
};
}
fingerprint_tuples! {
(0 A)
(0 A, 1 B)
(0 A, 1 B, 2 C)
(0 A, 1 B, 2 C, 3 D)
(0 A, 1 B, 2 C, 3 D, 4 E)
(0 A, 1 B, 2 C, 3 D, 4 E, 5 F)
}
fn fingerprint_unordered<I, F>(hasher: &mut Hasher, len: usize, items: I, mut each: F)
where
F: FnMut(&mut Hasher, I::Item),
I: Iterator,
{
let mut combined = 0u64;
for item in items {
let mut element = Hasher::new();
each(&mut element, item);
combined ^= element.finish();
}
hasher.write_u64(len as u64);
hasher.write_u64(combined);
}
impl<T: Fingerprint, S> Fingerprint for HashSet<T, S> {
fn fingerprint(&self, hasher: &mut Hasher) {
fingerprint_unordered(hasher, self.len(), self.iter(), |h, item| {
item.fingerprint(h)
});
}
}
impl<T: Fingerprint> Fingerprint for BTreeSet<T> {
fn fingerprint(&self, hasher: &mut Hasher) {
fingerprint_unordered(hasher, self.len(), self.iter(), |h, item| {
item.fingerprint(h)
});
}
}
impl<K: Fingerprint, V: Fingerprint, S> Fingerprint for HashMap<K, V, S> {
fn fingerprint(&self, hasher: &mut Hasher) {
fingerprint_unordered(hasher, self.len(), self.iter(), |h, (key, value)| {
key.fingerprint(h);
value.fingerprint(h);
});
}
}
impl<K: Fingerprint, V: Fingerprint> Fingerprint for BTreeMap<K, V> {
fn fingerprint(&self, hasher: &mut Hasher) {
fingerprint_unordered(hasher, self.len(), self.iter(), |h, (key, value)| {
key.fingerprint(h);
value.fingerprint(h);
});
}
}