musli_zerocopy/phf/
hashing.rs1use core::hash::Hash;
2
3use crate::buf::{Buf, Visit};
4use crate::error::{Error, ErrorKind};
5use crate::phf::Entry;
6use crate::sip::{Hash128, Hasher128, SipHasher13};
7
8#[non_exhaustive]
9pub(crate) struct Hashes {
10 pub(crate) g: usize,
11 pub(crate) f1: u32,
12 pub(crate) f2: u32,
13}
14
15pub(crate) type HashKey = u64;
16
17#[inline]
18pub(crate) fn displace(f1: u32, f2: u32, d1: u32, d2: u32) -> u32 {
19 d2.wrapping_add(f1.wrapping_mul(d1)).wrapping_add(f2)
20}
21
22#[inline]
23pub(crate) fn hash<T>(buf: &Buf, value: &T, key: &HashKey) -> Result<Hashes, Error>
24where
25 T: ?Sized + Visit,
26 T::Target: Hash,
27{
28 let mut hasher = SipHasher13::new_with_keys(0, *key);
29 value.visit(buf, |value| value.hash(&mut hasher))?;
30
31 let Hash128 { h1, h2 } = hasher.finish128();
32
33 Ok(Hashes {
34 g: (h1 >> 32) as usize,
35 f1: h1 as u32,
36 f2: h2 as u32,
37 })
38}
39
40#[inline]
41pub(crate) fn get_index(
42 &Hashes { g, f1, f2 }: &Hashes,
43 displacements: &[Entry<u32, u32>],
44 len: usize,
45) -> Result<usize, Error> {
46 let index = g % displacements.len();
47
48 let Some(&Entry { key: d1, value: d2 }) = displacements.get(index) else {
49 return Err(Error::new(ErrorKind::IndexOutOfBounds {
50 index,
51 len: displacements.len(),
52 }));
53 };
54
55 Ok(displace(f1, f2, d1, d2) as usize % len)
56}
57
58#[inline]
59pub(crate) fn get_custom_index<'a, D>(
60 &Hashes { g, f1, f2 }: &Hashes,
61 get: D,
62 displacements_len: usize,
63 len: usize,
64) -> Result<usize, Error>
65where
66 D: FnOnce(usize) -> Result<Option<&'a Entry<u32, u32>>, Error>,
67{
68 let index = g % displacements_len;
69
70 let Some(&Entry { key: d1, value: d2 }) = get(index)? else {
71 return Err(Error::new(ErrorKind::IndexOutOfBounds {
72 index,
73 len: displacements_len,
74 }));
75 };
76
77 Ok(displace(f1, f2, d1, d2) as usize % len)
78}