use std::hash::Hasher;
use std::os::raw::c_void;
use std::ptr::NonNull;
use crate::ffi;
use crate::hasher::{FastHash, FastHasher, HasherExt, StreamHasher};
#[derive(Clone, Default)]
pub struct Hash32;
impl FastHash for Hash32 {
type Hash = u32;
type Seed = u32;
#[inline(always)]
fn hash_with_seed<T: AsRef<[u8]>>(bytes: T, seed: u32) -> u32 {
let mut hash1 = u64::from(seed);
let mut hash2 = u64::from(seed);
unsafe {
ffi::SpookyHasherHash(
bytes.as_ref().as_ptr() as *const c_void,
bytes.as_ref().len(),
&mut hash1,
&mut hash2,
);
}
hash1 as u32
}
}
trivial_hasher! {
Hasher32(Hash32) -> u32
}
#[derive(Clone, Default)]
pub struct Hash64;
impl FastHash for Hash64 {
type Hash = u64;
type Seed = u64;
#[inline(always)]
fn hash_with_seed<T: AsRef<[u8]>>(bytes: T, seed: u64) -> u64 {
let mut hash1 = seed;
let mut hash2 = seed;
unsafe {
ffi::SpookyHasherHash(
bytes.as_ref().as_ptr() as *const c_void,
bytes.as_ref().len(),
&mut hash1,
&mut hash2,
);
}
hash1
}
}
trivial_hasher! {
Hasher64(Hash64) -> u64
}
#[derive(Clone, Default)]
pub struct Hash128;
impl FastHash for Hash128 {
type Hash = u128;
type Seed = u128;
#[inline(always)]
fn hash_with_seed<T: AsRef<[u8]>>(bytes: T, seed: u128) -> u128 {
let mut hi = (seed >> 64) as u64;
let mut lo = seed as u64;
unsafe {
ffi::SpookyHasherHash(
bytes.as_ref().as_ptr() as *const c_void,
bytes.as_ref().len(),
&mut hi,
&mut lo,
);
}
u128::from(hi).wrapping_shl(64) + u128::from(lo)
}
}
#[derive(Clone)]
pub struct Hasher128(NonNull<c_void>);
impl Default for Hasher128 {
fn default() -> Self {
Self::new()
}
}
impl Drop for Hasher128 {
#[inline(always)]
fn drop(&mut self) {
unsafe { ffi::SpookyHasherFree(self.0.as_ptr()) }
}
}
impl Hasher for Hasher128 {
#[inline(always)]
fn finish(&self) -> u64 {
self.finish_ext() as u64
}
#[inline(always)]
fn write(&mut self, bytes: &[u8]) {
unsafe {
ffi::SpookyHasherUpdate(
self.0.as_ptr(),
bytes.as_ptr() as *const c_void,
bytes.len(),
)
}
}
}
impl HasherExt for Hasher128 {
#[inline(always)]
fn finish_ext(&self) -> u128 {
let mut hi = 0_u64;
let mut lo = 0_u64;
unsafe {
ffi::SpookyHasherFinal(self.0.as_ptr(), &mut hi, &mut lo);
}
u128::from(hi).wrapping_shl(64) + u128::from(lo)
}
}
impl FastHasher for Hasher128 {
type Seed = (u64, u64);
type Output = u128;
#[inline(always)]
fn with_seed(seed: Self::Seed) -> Hasher128 {
unsafe {
let h = ffi::SpookyHasherNew();
ffi::SpookyHasherInit(h, seed.0, seed.1);
Hasher128(NonNull::new_unchecked(h))
}
}
}
impl StreamHasher for Hasher128 {}
impl_build_hasher!(Hasher128, Hash128);
#[inline(always)]
pub fn hash32<T: AsRef<[u8]>>(v: T) -> u32 {
Hash32::hash(v)
}
#[inline(always)]
pub fn hash32_with_seed<T: AsRef<[u8]>>(v: T, seed: u32) -> u32 {
Hash32::hash_with_seed(v, seed)
}
#[inline(always)]
pub fn hash64<T: AsRef<[u8]>>(v: T) -> u64 {
Hash64::hash(v)
}
#[inline(always)]
pub fn hash64_with_seed<T: AsRef<[u8]>>(v: T, seed: u64) -> u64 {
Hash64::hash_with_seed(v, seed)
}
#[inline(always)]
pub fn hash128<T: AsRef<[u8]>>(v: T) -> u128 {
Hash128::hash(v)
}
#[inline(always)]
pub fn hash128_with_seed<T: AsRef<[u8]>>(v: T, seed: u128) -> u128 {
Hash128::hash_with_seed(v, seed)
}