use core::fmt;
use std::any::Any;
use std::hash::{Hash, Hasher};
use std::ops::Deref;
use base64::Engine;
use fxhash::FxHasher32;
use siphasher::sip128::{Hasher128, SipHasher13};
#[cfg(feature = "rkyv")]
use rkyv::{Archive, Deserialize as rDeser, Serialize as rSer};
use crate::error::prelude::Result;
pub(crate) type FxBuildHasher = std::hash::BuildHasherDefault<FxHasher>;
pub use rustc_hash::{FxHashMap, FxHashSet, FxHasher};
pub type FxDashMap<K, V> = dashmap::DashMap<K, V, FxBuildHasher>;
#[derive(Clone, Copy, Hash, PartialEq, Eq, PartialOrd, Ord)]
#[cfg_attr(feature = "rkyv", derive(Archive, rDeser, rSer))]
#[cfg_attr(feature = "rkyv-validation", archive(check_bytes))]
pub struct Fingerprint {
lo: u64,
hi: u64,
}
impl fmt::Debug for Fingerprint {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.write_str(&self.as_svg_id("fg"))
}
}
impl serde::Serialize for Fingerprint {
fn serialize<S: serde::Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
serializer.serialize_str(&self.as_svg_id(""))
}
}
impl<'de> serde::Deserialize<'de> for Fingerprint {
fn deserialize<D: serde::Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
let s = <std::string::String as serde::Deserialize>::deserialize(deserializer)?;
Fingerprint::try_from_str(&s).map_err(serde::de::Error::custom)
}
}
impl Fingerprint {
pub fn from_pair(lo: u64, hi: u64) -> Self {
Self { lo, hi }
}
pub const fn from_u128(hash: u128) -> Self {
Self {
lo: hash as u64,
hi: (hash >> 64) as u64,
}
}
pub fn to_u128(self) -> u128 {
((self.hi as u128) << 64) | self.lo as u128
}
pub fn lower32(self) -> u32 {
self.lo as u32
}
pub fn try_from_str(s: &str) -> Result<Self> {
let bytes = base64::engine::general_purpose::STANDARD_NO_PAD
.decode(&s.as_bytes()[..11])
.expect("invalid base64 string");
let lo = u64::from_le_bytes(bytes.try_into().unwrap());
let mut bytes = base64::engine::general_purpose::STANDARD_NO_PAD
.decode(&s.as_bytes()[11..])
.expect("invalid base64 string");
bytes.resize(8, 0);
let hi = u64::from_le_bytes(bytes.try_into().unwrap());
Ok(Self::from_pair(lo, hi))
}
#[comemo::memoize]
pub fn as_svg_id(self, prefix: &'static str) -> String {
let fingerprint_lo =
base64::engine::general_purpose::STANDARD_NO_PAD.encode(self.lo.to_le_bytes());
if self.hi == 0 {
return [prefix, &fingerprint_lo].join("");
}
let fingerprint_hi = {
let id = self.hi.to_le_bytes();
let rev_zero = id.iter().rev().skip_while(|&&b| b == 0).count();
let id = &id[..rev_zero];
base64::engine::general_purpose::STANDARD_NO_PAD.encode(id)
};
[prefix, &fingerprint_lo, &fingerprint_hi].join("")
}
}
pub trait FingerprintHasher: std::hash::Hasher {
fn finish_fingerprint(self) -> (Fingerprint, Vec<u8>);
}
#[derive(Default)]
pub struct FingerprintSipHasher {
data: Vec<u8>,
}
pub type FingerprintSipHasherBase = SipHasher13;
impl FingerprintSipHasher {
pub fn fast_hash(&self) -> (u32, &Vec<u8>) {
let mut inner = FxHasher32::default();
self.data.hash(&mut inner);
(inner.finish() as u32, &self.data)
}
}
impl std::hash::Hasher for FingerprintSipHasher {
fn write(&mut self, bytes: &[u8]) {
self.data.extend_from_slice(bytes);
}
fn finish(&self) -> u64 {
let mut inner = FingerprintSipHasherBase::default();
self.data.hash(&mut inner);
inner.finish()
}
}
impl FingerprintHasher for FingerprintSipHasher {
fn finish_fingerprint(self) -> (Fingerprint, Vec<u8>) {
let buffer = self.data.clone();
let mut inner = FingerprintSipHasherBase::default();
buffer.hash(&mut inner);
let hash = inner.finish128();
(
Fingerprint {
lo: hash.h1,
hi: hash.h2,
},
buffer,
)
}
}
#[derive(Default)]
pub struct FingerprintBuilder {
#[cfg(feature = "bi-hash")]
fast_conflict_checker: crate::adt::CHashMap<u32, Vec<u8>>,
conflict_checker: crate::adt::CHashMap<Fingerprint, Vec<u8>>,
}
#[cfg(not(feature = "bi-hash"))]
impl FingerprintBuilder {
pub fn resolve_unchecked<T: Hash>(&self, item: &T) -> Fingerprint {
let mut s = FingerprintSipHasher { data: Vec::new() };
item.hash(&mut s);
let (fingerprint, _featured_data) = s.finish_fingerprint();
fingerprint
}
pub fn resolve<T: Hash + 'static>(&self, item: &T) -> Fingerprint {
let mut s = FingerprintSipHasher { data: Vec::new() };
item.type_id().hash(&mut s);
item.hash(&mut s);
let (fingerprint, featured_data) = s.finish_fingerprint();
let Some(prev_featured_data) = self.conflict_checker.get(&fingerprint) else {
self.conflict_checker.insert(fingerprint, featured_data);
return fingerprint;
};
if *prev_featured_data == *featured_data {
return fingerprint;
}
panic!("Fingerprint conflict detected!");
}
}
#[cfg(feature = "bi-hash")]
impl FingerprintBuilder {
pub fn resolve_unchecked<T: Hash>(&self, item: &T) -> Fingerprint {
let mut s = FingerprintSipHasher { data: Vec::new() };
item.hash(&mut s);
let (fingerprint, featured_data) = s.fast_hash();
let Some(prev_featured_data) = self.fast_conflict_checker.get(&fingerprint) else {
self.fast_conflict_checker.insert(fingerprint, s.data);
return Fingerprint::from_pair(fingerprint as u64, 0);
};
if *prev_featured_data == *featured_data {
return Fingerprint::from_pair(fingerprint as u64, 0);
}
let (fingerprint, _featured_data) = s.finish_fingerprint();
fingerprint
}
pub fn resolve<T: Hash + 'static>(&self, item: &T) -> Fingerprint {
let mut s = FingerprintSipHasher { data: Vec::new() };
item.type_id().hash(&mut s);
item.hash(&mut s);
let (fingerprint, featured_data) = s.fast_hash();
let Some(prev_featured_data) = self.fast_conflict_checker.get(&fingerprint) else {
self.fast_conflict_checker.insert(fingerprint, s.data);
return Fingerprint::from_pair(fingerprint as u64, 0);
};
if *prev_featured_data == *featured_data {
return Fingerprint::from_pair(fingerprint as u64, 0);
}
let (fingerprint, featured_data) = s.finish_fingerprint();
let Some(prev_featured_data) = self.conflict_checker.get(&fingerprint) else {
self.conflict_checker.insert(fingerprint, featured_data);
return fingerprint;
};
if *prev_featured_data == *featured_data {
return fingerprint;
}
panic!("Fingerprint conflict detected!");
}
}
pub fn item_hash128<T: Hash + 'static>(item: &T) -> u128 {
let mut state = SipHasher13::new();
item.type_id().hash(&mut state);
item.hash(&mut state);
state.finish128().as_u128()
}
#[inline]
pub fn hash128<T: std::hash::Hash>(value: &T) -> u128 {
let mut state = SipHasher13::new();
value.hash(&mut state);
state.finish128().as_u128()
}
#[inline]
pub fn hash64<T: Hash + ?Sized>(v: &T) -> u64 {
let mut state = FxHasher::default();
v.hash(&mut state);
state.finish()
}
pub use fxhash::hash32;
pub trait StaticHash128 {
fn get_hash(&self) -> u128;
}
impl Hash for dyn StaticHash128 {
#[inline]
fn hash<H: Hasher>(&self, state: &mut H) {
state.write_u128(self.get_hash());
}
}
pub struct HashedTrait<T: ?Sized> {
hash: u128,
t: Box<T>,
}
impl<T: ?Sized> HashedTrait<T> {
pub fn new(hash: u128, t: Box<T>) -> Self {
Self { hash, t }
}
}
impl<T: ?Sized> Deref for HashedTrait<T> {
type Target = T;
fn deref(&self) -> &Self::Target {
&self.t
}
}
impl<T> Hash for HashedTrait<T> {
#[inline]
fn hash<H: Hasher>(&self, state: &mut H) {
state.write_u128(self.hash);
}
}
impl<T: Hash + Default + 'static> Default for HashedTrait<T> {
fn default() -> Self {
let t = T::default();
Self {
hash: item_hash128(&t),
t: Box::new(t),
}
}
}
impl<T: ?Sized> StaticHash128 for HashedTrait<T> {
fn get_hash(&self) -> u128 {
self.hash
}
}
#[test]
fn test_fingerprint() {
let t = Fingerprint::from_pair(0, 1);
assert_eq!(Fingerprint::try_from_str(&t.as_svg_id("")).unwrap(), t);
let t = Fingerprint::from_pair(1, 1);
assert_eq!(Fingerprint::try_from_str(&t.as_svg_id("")).unwrap(), t);
let t = Fingerprint::from_pair(1, 0);
assert_eq!(Fingerprint::try_from_str(&t.as_svg_id("")).unwrap(), t);
let t = Fingerprint::from_pair(0, 0);
assert_eq!(Fingerprint::try_from_str(&t.as_svg_id("")).unwrap(), t);
}