use core::hash::Hasher;
use crate::rapid_const::{rapidhash_core, rapidhash_finish, rapidhash_seed, RAPID_SEED};
#[derive(Copy, Clone, Eq, PartialEq)]
pub struct RapidInlineHasher {
seed: u64,
a: u64,
b: u64,
size: u64,
}
pub type RapidInlineHashBuilder = core::hash::BuildHasherDefault<RapidInlineHasher>;
#[cfg(any(feature = "std", docsrs))]
pub type RapidInlineHashMap<K, V> = std::collections::HashMap<K, V, RapidInlineHashBuilder>;
#[cfg(any(feature = "std", docsrs))]
pub type RapidInlineHashSet<K> = std::collections::HashSet<K, RapidInlineHashBuilder>;
impl RapidInlineHasher {
pub const DEFAULT_SEED: u64 = RAPID_SEED;
#[inline(always)]
#[must_use]
pub const fn new(seed: u64) -> Self {
Self {
seed,
a: 0,
b: 0,
size: 0,
}
}
#[inline(always)]
#[must_use]
pub const fn default_const() -> Self {
Self::new(Self::DEFAULT_SEED)
}
#[inline(always)]
#[must_use]
pub const fn write_const(&self, bytes: &[u8]) -> Self {
const _: () = assert!(
usize::MAX as u128 <= u64::MAX as u128,
"usize is wider than u64. Please raise a github issue to support this."
);
let mut this = *self;
this.size += bytes.len() as u64;
this.seed = rapidhash_seed(this.seed, this.size);
let (a, b, seed) = rapidhash_core(this.a, this.b, this.seed, bytes);
this.a = a;
this.b = b;
this.seed = seed;
this
}
#[inline(always)]
#[must_use]
pub const fn finish_const(&self) -> u64 {
rapidhash_finish(self.a, self.b, self.size)
}
}
impl Default for RapidInlineHasher {
#[inline(always)]
fn default() -> Self {
Self::new(RAPID_SEED)
}
}
impl Hasher for RapidInlineHasher {
#[inline(always)]
fn finish(&self) -> u64 {
self.finish_const()
}
#[inline(always)]
fn write(&mut self, bytes: &[u8]) {
*self = self.write_const(bytes);
}
#[inline(always)]
fn write_u8(&mut self, i: u8) {
*self = self.write_const(&i.to_ne_bytes());
}
#[inline(always)]
fn write_u16(&mut self, i: u16) {
*self = self.write_const(&i.to_ne_bytes());
}
#[inline(always)]
fn write_u32(&mut self, i: u32) {
*self = self.write_const(&i.to_ne_bytes());
}
#[inline(always)]
fn write_u64(&mut self, i: u64) {
*self = self.write_const(&i.to_ne_bytes());
}
#[inline(always)]
fn write_u128(&mut self, i: u128) {
*self = self.write_const(&i.to_ne_bytes());
}
#[inline(always)]
fn write_usize(&mut self, i: usize) {
*self = self.write_const(&i.to_ne_bytes());
}
#[inline(always)]
fn write_i8(&mut self, i: i8) {
*self = self.write_const(&i.to_ne_bytes());
}
#[inline(always)]
fn write_i16(&mut self, i: i16) {
*self = self.write_const(&i.to_ne_bytes());
}
#[inline(always)]
fn write_i32(&mut self, i: i32) {
*self = self.write_const(&i.to_ne_bytes());
}
#[inline(always)]
fn write_i64(&mut self, i: i64) {
*self = self.write_const(&i.to_ne_bytes());
}
#[inline(always)]
fn write_i128(&mut self, i: i128) {
*self = self.write_const(&i.to_ne_bytes());
}
#[inline(always)]
fn write_isize(&mut self, i: isize) {
*self = self.write_const(&i.to_ne_bytes());
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_hasher_write_u64() {
assert_eq!((8 & 24) >> (8 >> 3), 4);
let ints = [
1234u64,
0,
1,
u64::MAX,
u64::MAX - 2385962040453523
];
for int in ints {
let mut hasher = RapidInlineHasher::default();
hasher.write(int.to_ne_bytes().as_slice());
let a = hasher.finish();
assert_eq!(int.to_ne_bytes().as_slice().len(), 8);
let mut hasher = RapidInlineHasher::default();
hasher.write_u64(int);
let b = hasher.finish();
assert_eq!(a, b, "Mismatching hash for u64 with input {int}");
}
}
}