1use core::fmt;
5use std::any::Any;
6use std::hash::{Hash, Hasher};
7use std::ops::Deref;
8
9use base64::Engine;
10use fxhash::FxHasher32;
11use siphasher::sip128::{Hasher128, SipHasher13};
12
13#[cfg(feature = "rkyv")]
14use rkyv::{Archive, Deserialize as rDeser, Serialize as rSer};
15
16use crate::error::prelude::Result;
17
18pub(crate) type FxBuildHasher = std::hash::BuildHasherDefault<FxHasher>;
19pub use rustc_hash::{FxHashMap, FxHashSet, FxHasher};
20pub type FxDashMap<K, V> = dashmap::DashMap<K, V, FxBuildHasher>;
24
25#[derive(Clone, Copy, Hash, PartialEq, Eq, PartialOrd, Ord)]
39#[cfg_attr(feature = "rkyv", derive(Archive, rDeser, rSer))]
40#[cfg_attr(feature = "rkyv-validation", archive(check_bytes))]
41pub struct Fingerprint {
42 lo: u64,
43 hi: u64,
44}
45
46impl fmt::Debug for Fingerprint {
47 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
48 f.write_str(&self.as_svg_id("fg"))
49 }
50}
51
52impl serde::Serialize for Fingerprint {
53 fn serialize<S: serde::Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
54 serializer.serialize_str(&self.as_svg_id(""))
55 }
56}
57
58impl<'de> serde::Deserialize<'de> for Fingerprint {
59 fn deserialize<D: serde::Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
60 let s = <std::string::String as serde::Deserialize>::deserialize(deserializer)?;
61 Fingerprint::try_from_str(&s).map_err(serde::de::Error::custom)
62 }
63}
64
65impl Fingerprint {
66 pub fn from_pair(lo: u64, hi: u64) -> Self {
68 Self { lo, hi }
69 }
70
71 pub const fn from_u128(hash: u128) -> Self {
73 Self {
75 lo: hash as u64,
76 hi: (hash >> 64) as u64,
77 }
78 }
79
80 pub fn to_u128(self) -> u128 {
82 ((self.hi as u128) << 64) | self.lo as u128
83 }
84
85 pub fn lower32(self) -> u32 {
90 self.lo as u32
91 }
92
93 pub fn try_from_str(s: &str) -> Result<Self> {
97 let bytes = base64::engine::general_purpose::STANDARD_NO_PAD
98 .decode(&s.as_bytes()[..11])
99 .expect("invalid base64 string");
100 let lo = u64::from_le_bytes(bytes.try_into().unwrap());
101 let mut bytes = base64::engine::general_purpose::STANDARD_NO_PAD
102 .decode(&s.as_bytes()[11..])
103 .expect("invalid base64 string");
104 bytes.resize(8, 0);
105 let hi = u64::from_le_bytes(bytes.try_into().unwrap());
106 Ok(Self::from_pair(lo, hi))
107 }
108
109 #[comemo::memoize]
113 pub fn as_svg_id(self, prefix: &'static str) -> String {
114 let fingerprint_lo =
115 base64::engine::general_purpose::STANDARD_NO_PAD.encode(self.lo.to_le_bytes());
116 if self.hi == 0 {
117 return [prefix, &fingerprint_lo].join("");
118 }
119
120 let fingerprint_hi = {
122 let id = self.hi.to_le_bytes();
123 let rev_zero = id.iter().rev().skip_while(|&&b| b == 0).count();
125 let id = &id[..rev_zero];
126 base64::engine::general_purpose::STANDARD_NO_PAD.encode(id)
127 };
128 [prefix, &fingerprint_lo, &fingerprint_hi].join("")
129 }
130}
131
132pub trait FingerprintHasher: std::hash::Hasher {
134 fn finish_fingerprint(self) -> (Fingerprint, Vec<u8>);
137}
138
139#[derive(Default)]
141pub struct FingerprintSipHasher {
142 data: Vec<u8>,
144}
145
146pub type FingerprintSipHasherBase = SipHasher13;
148
149impl FingerprintSipHasher {
150 pub fn fast_hash(&self) -> (u32, &Vec<u8>) {
152 let mut inner = FxHasher32::default();
153 self.data.hash(&mut inner);
154 (inner.finish() as u32, &self.data)
155 }
156}
157
158impl std::hash::Hasher for FingerprintSipHasher {
159 fn write(&mut self, bytes: &[u8]) {
160 self.data.extend_from_slice(bytes);
161 }
162
163 fn finish(&self) -> u64 {
164 let mut inner = FingerprintSipHasherBase::default();
165 self.data.hash(&mut inner);
166 inner.finish()
167 }
168}
169
170impl FingerprintHasher for FingerprintSipHasher {
171 fn finish_fingerprint(self) -> (Fingerprint, Vec<u8>) {
172 let buffer = self.data.clone();
173 let mut inner = FingerprintSipHasherBase::default();
174 buffer.hash(&mut inner);
175 let hash = inner.finish128();
176 (
177 Fingerprint {
178 lo: hash.h1,
179 hi: hash.h2,
180 },
181 buffer,
182 )
183 }
184}
185
186#[derive(Default)]
190pub struct FingerprintBuilder {
191 #[cfg(feature = "bi-hash")]
193 fast_conflict_checker: crate::adt::CHashMap<u32, Vec<u8>>,
194 conflict_checker: crate::adt::CHashMap<Fingerprint, Vec<u8>>,
196}
197
198#[cfg(not(feature = "bi-hash"))]
199impl FingerprintBuilder {
200 pub fn resolve_unchecked<T: Hash>(&self, item: &T) -> Fingerprint {
202 let mut s = FingerprintSipHasher { data: Vec::new() };
203 item.hash(&mut s);
204 let (fingerprint, _featured_data) = s.finish_fingerprint();
205 fingerprint
206 }
207
208 pub fn resolve<T: Hash + 'static>(&self, item: &T) -> Fingerprint {
210 let mut s = FingerprintSipHasher { data: Vec::new() };
211 item.type_id().hash(&mut s);
212 item.hash(&mut s);
213
214 let (fingerprint, featured_data) = s.finish_fingerprint();
215 let Some(prev_featured_data) = self.conflict_checker.get(&fingerprint) else {
216 self.conflict_checker.insert(fingerprint, featured_data);
217 return fingerprint;
218 };
219
220 if *prev_featured_data == *featured_data {
221 return fingerprint;
222 }
223
224 panic!("Fingerprint conflict detected!");
226 }
227}
228
229#[cfg(feature = "bi-hash")]
230impl FingerprintBuilder {
231 pub fn resolve_unchecked<T: Hash>(&self, item: &T) -> Fingerprint {
233 let mut s = FingerprintSipHasher { data: Vec::new() };
234 item.hash(&mut s);
235 let (fingerprint, featured_data) = s.fast_hash();
236 let Some(prev_featured_data) = self.fast_conflict_checker.get(&fingerprint) else {
237 self.fast_conflict_checker.insert(fingerprint, s.data);
238 return Fingerprint::from_pair(fingerprint as u64, 0);
239 };
240
241 if *prev_featured_data == *featured_data {
242 return Fingerprint::from_pair(fingerprint as u64, 0);
243 }
244
245 let (fingerprint, _featured_data) = s.finish_fingerprint();
246 fingerprint
247 }
248
249 pub fn resolve<T: Hash + 'static>(&self, item: &T) -> Fingerprint {
252 let mut s = FingerprintSipHasher { data: Vec::new() };
253 item.type_id().hash(&mut s);
254 item.hash(&mut s);
255 let (fingerprint, featured_data) = s.fast_hash();
256 let Some(prev_featured_data) = self.fast_conflict_checker.get(&fingerprint) else {
257 self.fast_conflict_checker.insert(fingerprint, s.data);
258 return Fingerprint::from_pair(fingerprint as u64, 0);
259 };
260
261 if *prev_featured_data == *featured_data {
262 return Fingerprint::from_pair(fingerprint as u64, 0);
263 }
264
265 let (fingerprint, featured_data) = s.finish_fingerprint();
266 let Some(prev_featured_data) = self.conflict_checker.get(&fingerprint) else {
267 self.conflict_checker.insert(fingerprint, featured_data);
268 return fingerprint;
269 };
270
271 if *prev_featured_data == *featured_data {
272 return fingerprint;
273 }
274
275 panic!("Fingerprint conflict detected!");
277 }
278}
279
280pub fn item_hash128<T: Hash + 'static>(item: &T) -> u128 {
286 let mut state = SipHasher13::new();
289 item.type_id().hash(&mut state);
290 item.hash(&mut state);
291 state.finish128().as_u128()
292}
293
294#[inline]
298pub fn hash128<T: std::hash::Hash>(value: &T) -> u128 {
299 let mut state = SipHasher13::new();
300 value.hash(&mut state);
301 state.finish128().as_u128()
302}
303
304#[inline]
306pub fn hash64<T: Hash + ?Sized>(v: &T) -> u64 {
307 let mut state = FxHasher::default();
308 v.hash(&mut state);
309 state.finish()
310}
311
312pub use fxhash::hash32;
314
315pub trait StaticHash128 {
317 fn get_hash(&self) -> u128;
319}
320
321impl Hash for dyn StaticHash128 {
322 #[inline]
323 fn hash<H: Hasher>(&self, state: &mut H) {
324 state.write_u128(self.get_hash());
325 }
326}
327
328pub struct HashedTrait<T: ?Sized> {
333 hash: u128,
334 t: Box<T>,
335}
336
337impl<T: ?Sized> HashedTrait<T> {
338 pub fn new(hash: u128, t: Box<T>) -> Self {
340 Self { hash, t }
341 }
342}
343
344impl<T: ?Sized> Deref for HashedTrait<T> {
345 type Target = T;
346
347 fn deref(&self) -> &Self::Target {
348 &self.t
349 }
350}
351
352impl<T> Hash for HashedTrait<T> {
353 #[inline]
354 fn hash<H: Hasher>(&self, state: &mut H) {
355 state.write_u128(self.hash);
356 }
357}
358
359impl<T: Hash + Default + 'static> Default for HashedTrait<T> {
360 fn default() -> Self {
361 let t = T::default();
362 Self {
363 hash: item_hash128(&t),
364 t: Box::new(t),
365 }
366 }
367}
368
369impl<T: ?Sized> StaticHash128 for HashedTrait<T> {
370 fn get_hash(&self) -> u128 {
371 self.hash
372 }
373}
374
375#[test]
376fn test_fingerprint() {
377 let t = Fingerprint::from_pair(0, 1);
378 assert_eq!(Fingerprint::try_from_str(&t.as_svg_id("")).unwrap(), t);
379
380 let t = Fingerprint::from_pair(1, 1);
381 assert_eq!(Fingerprint::try_from_str(&t.as_svg_id("")).unwrap(), t);
382
383 let t = Fingerprint::from_pair(1, 0);
384 assert_eq!(Fingerprint::try_from_str(&t.as_svg_id("")).unwrap(), t);
385
386 let t = Fingerprint::from_pair(0, 0);
387 assert_eq!(Fingerprint::try_from_str(&t.as_svg_id("")).unwrap(), t);
388}