use helper;
fn read_int(int: &[u8]) -> u64 {
debug_assert!(
int.len() <= 8,
"The buffer length of the integer must be less than or equal to \
the one of an u64."
);
let mut x = 0;
for &i in int.iter().rev() {
x <<= 8;
x |= i as u64;
}
x
}
struct State {
a: u64,
b: u64,
c: u64,
d: u64,
}
impl State {
fn write_u64(&mut self, x: u64) {
let mut a = self.a;
a = helper::diffuse(a ^ x);
self.a = self.b;
self.b = self.c;
self.c = self.d;
self.d = a;
}
fn finish(self, total: usize) -> u64 {
helper::diffuse(
self.a ^ self.b ^ self.c ^ self.d
^ total as u64,
)
}
fn with_seeds(k1: u64, k2: u64, k3: u64, k4: u64) -> State {
State {
a: k1,
b: k2,
c: k3,
d: k4,
}
}
}
pub fn hash(buf: &[u8]) -> u64 {
hash_seeded(
buf,
0x16f11fe89b0d677c,
0xb480a793d8e6c86c,
0x6fe2e5aaf078ebc9,
0x14f994a4c5259381,
)
}
pub fn hash_seeded(buf: &[u8], k1: u64, k2: u64, k3: u64, k4: u64) -> u64 {
let mut state = State::with_seeds(k1, k2, k3, k4);
for int in buf.chunks(8) {
state.write_u64(read_int(int));
}
state.finish(buf.len())
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn shakespear() {
assert_eq!(hash(b"to be or not to be"), 1988685042348123509);
}
}