use core::convert::TryInto;
use core::ops::BitXor;
const ROTATE: u32 = 5;
const SEED64: u64 = 0x517cc1b727220a95;
const SEED32: u32 = (SEED64 & 0xFFFF_FFFF) as u32;
#[cfg(target_pointer_width = "32")]
const SEED: usize = SEED32 as usize;
#[cfg(target_pointer_width = "64")]
const SEED: usize = SEED64 as usize;
trait HashWord {
fn hash_word(&mut self, word: Self);
}
impl HashWord for usize {
#[inline]
fn hash_word(&mut self, word: Self) {
*self = self.rotate_left(ROTATE).bitxor(word).wrapping_mul(SEED);
}
}
impl HashWord for u32 {
#[inline]
fn hash_word(&mut self, word: Self) {
*self = self.rotate_left(ROTATE).bitxor(word).wrapping_mul(SEED32);
}
}
impl HashWord for u64 {
#[inline]
fn hash_word(&mut self, word: Self) {
*self = self.rotate_left(ROTATE).bitxor(word).wrapping_mul(SEED64);
}
}
#[cfg(target_endian = "little")]
fn read_u32(buf: &[u8]) -> u32 {
u32::from_le_bytes(buf[..4].try_into().unwrap())
}
#[cfg(target_endian = "little")]
fn read_u64(buf: &[u8]) -> u64 {
u64::from_le_bytes(buf[..8].try_into().unwrap())
}
#[cfg(target_endian = "big")]
fn read_u32(buf: &[u8]) -> u32 {
u32::from_be_bytes(buf[..4].try_into().unwrap())
}
#[cfg(target_endian = "big")]
fn read_u64(buf: &[u8]) -> u64 {
u64::from_be_bytes(buf[..8].try_into().unwrap())
}
#[inline]
#[cfg(target_pointer_width = "32")]
fn write(initial_state: usize, mut bytes: &[u8]) -> usize {
let mut hash = initial_state as u32;
while bytes.len() >= 4 {
let n = read_u32(bytes);
hash.hash_word(n);
bytes = bytes.split_at(4).1;
}
for byte in bytes {
hash.hash_word(*byte as u32);
}
hash as usize
}
#[inline]
#[cfg(target_pointer_width = "64")]
fn write(initial_state: usize, mut bytes: &[u8]) -> usize {
let mut hash = initial_state as u64;
while bytes.len() >= 8 {
let n = read_u64(bytes);
hash.hash_word(n);
bytes = bytes.split_at(8).1;
}
if bytes.len() >= 4 {
let n = read_u32(bytes);
hash.hash_word(n as u64);
bytes = bytes.split_at(4).1;
}
for byte in bytes {
hash.hash_word(*byte as u64);
}
hash as usize
}
pub fn hash(bytes: &[u8]) -> usize {
write(0usize, bytes)
}