#![no_std]
const SEED_DEFAULT: u32 = 0x9E37_79B9;
const MUL_A: u32 = 0x85EB_CA6B;
const MUL_B: u32 = 0xC2B2_AE35;
const FINAL_XOR_1: u32 = 0x6B43_A9B5;
const FINAL_XOR_2: u32 = 0x52DC_E729;
#[inline(always)]
fn mix_word(acc: u32, word: u32) -> u32 {
let mut a = acc.wrapping_add(word.wrapping_mul(MUL_A));
a = a.rotate_left(13);
a ^ (a >> 7)
}
#[inline(always)]
fn mix_byte(acc: u32, byte: u8) -> u32 {
let v = (byte as u32).wrapping_mul(MUL_A);
let acc = acc.wrapping_add(v);
let acc = acc.rotate_left(13);
acc ^ (acc >> 7)
}
#[inline(always)]
fn finalize(mut h: u32, len: u32) -> u32 {
h = h.wrapping_add(len.wrapping_mul(MUL_A));
h ^= h >> 16;
h = h.wrapping_mul(FINAL_XOR_1);
h ^= h >> 13;
h = h.wrapping_mul(MUL_B);
h ^= h >> 16;
h ^ FINAL_XOR_2
}
#[inline]
pub fn mwhash(data: &[u8]) -> u32 {
Hasher::new().feed(data).finish()
}
#[inline]
pub fn mwhash_seeded(data: &[u8], seed: u32) -> u32 {
Hasher::with_seed(seed).feed(data).finish()
}
#[derive(Clone, Debug)]
pub struct Hasher {
acc: u32,
seed: u32,
len: u32,
tail: [u8; 4],
tail_len: usize,
}
impl Hasher {
#[inline]
pub const fn new() -> Self {
Self { acc: SEED_DEFAULT, seed: SEED_DEFAULT, len: 0, tail: [0; 4], tail_len: 0 }
}
#[inline]
pub const fn with_seed(seed: u32) -> Self {
Self { acc: seed, seed, len: 0, tail: [0; 4], tail_len: 0 }
}
pub fn update(&mut self, mut data: &[u8]) {
self.len = self.len.wrapping_add(data.len() as u32);
if self.tail_len > 0 {
let take = core::cmp::min(4 - self.tail_len, data.len());
self.tail[self.tail_len..self.tail_len + take].copy_from_slice(&data[..take]);
self.tail_len += take;
data = &data[take..];
if self.tail_len == 4 {
let word = u32::from_le_bytes(self.tail);
self.acc = mix_word(self.acc, word);
self.tail_len = 0;
}
}
let mut chunks = data.chunks_exact(4);
for chunk in &mut chunks {
let word = u32::from_le_bytes([chunk[0], chunk[1], chunk[2], chunk[3]]);
self.acc = mix_word(self.acc, word);
}
let rem = chunks.remainder();
if !rem.is_empty() {
self.tail[..rem.len()].copy_from_slice(rem);
self.tail_len = rem.len();
}
}
#[inline]
pub fn feed(&mut self, data: &[u8]) -> &mut Self {
self.update(data);
self
}
#[inline]
pub fn finish(&self) -> u32 {
let mut current_acc = self.acc;
for i in 0..self.tail_len {
current_acc = mix_byte(current_acc, self.tail[i]);
}
finalize(current_acc, self.len)
}
#[inline]
pub fn reset(&mut self) {
self.acc = self.seed;
self.len = 0;
self.tail_len = 0;
}
#[inline]
pub fn reset_with_seed(&mut self, seed: u32) {
self.seed = seed;
self.acc = seed;
self.len = 0;
self.tail_len = 0;
}
pub fn with_string_seed(seed: &str) -> Self {
let seed = mwhash(seed.as_bytes());
Self::with_seed(seed)
}
pub fn reset_with_string_seed(&mut self, seed: &str) {
let seed = mwhash(seed.as_bytes());
self.reset_with_seed(seed);
}
}
impl Default for Hasher {
fn default() -> Self { Self::new() }
}
#[inline]
pub fn mwhash_u32(value: u32) -> u32 { mwhash(&value.to_le_bytes()) }
#[inline]
pub fn mwhash_u64(value: u64) -> u32 { mwhash(&value.to_le_bytes()) }
#[inline]
pub fn mwhash_concat(a: &[u8], b: &[u8]) -> u32 {
let mut h = Hasher::new();
h.update(a);
h.update(b);
h.finish()
}