#[derive(Clone, Copy, PartialEq, Eq, Debug)]
pub struct SipHash {
first: u64,
second: u64,
third: u64,
fourth: u64,
}
impl SipHash {
#[must_use]
pub const fn seeded(seed: i64) -> Self {
let key_low = seed as u64;
let key_high = (seed as u64).rotate_left(32);
Self {
first: key_low ^ 0x736f_6d65_7073_6575,
second: key_high ^ 0x646f_7261_6e64_6f6d,
third: key_low ^ 0x6c79_6765_6e65_7261,
fourth: key_high ^ 0x7465_6462_7974_6573,
}
}
#[must_use]
pub const fn extended(parent: Self, message: i64) -> Self {
let mut first = parent.first;
let mut second = parent.second;
let mut third = parent.third;
let mut fourth = parent.fourth;
let mut round = 0;
while round < 2 {
first = first.wrapping_add(second);
third = third.wrapping_add(fourth);
second = second.rotate_left(13);
fourth = fourth.rotate_left(16);
second ^= first;
fourth ^= third;
first = first.rotate_left(32);
third = third.wrapping_add(second);
first = first.wrapping_add(fourth);
second = second.rotate_left(17);
fourth = fourth.rotate_left(21);
second ^= third;
fourth ^= first;
third = third.rotate_left(32);
round += 1;
}
first ^= message as u64;
Self {
first,
second,
third,
fourth,
}
}
#[must_use]
pub fn for_child(self, child_name: &str) -> Self {
Self::extended(
self,
i64::from(crate::hashing::utf16_string_hash(child_name)),
)
}
#[must_use]
pub const fn hash_code(self) -> i32 {
let folded = self.first ^ self.second ^ self.third ^ self.fourth;
(folded ^ (folded >> 16)) as i32
}
}
#[must_use]
pub fn hash_for_path(seed: i64, path: &str) -> SipHash {
let mut hash = SipHash::seeded(seed);
for element in path.split('/').filter(|element| !element.is_empty()) {
hash = hash.for_child(element);
}
hash
}
#[must_use]
pub const fn narrowed_seed(stored_seed: i64) -> i64 {
stored_seed as i32 as i64
}