use crate::crc32c::slice_by_8_with_seed;
use core::hash::{BuildHasher, BuildHasherDefault, Hasher};
#[derive(Debug, Default)]
pub struct CRC32CHasher {
key: u32,
}
impl CRC32CHasher {
pub fn with_seed(seed: u32) -> CRC32CHasher {
CRC32CHasher { key: seed }
}
}
impl Hasher for CRC32CHasher {
fn finish(&self) -> u64 {
self.key as u64
}
fn write(&mut self, bytes: &[u8]) {
self.key = slice_by_8_with_seed(bytes, self.key);
}
}
impl BuildHasher for CRC32CHasher {
type Hasher = CRC32CHasher;
fn build_hasher(&self) -> Self::Hasher {
CRC32CHasher::default()
}
}
pub type CRC32CBuildHasher = BuildHasherDefault<CRC32CHasher>;
#[cfg(test)]
mod tests {
use super::{CRC32CBuildHasher, CRC32CHasher};
use crate::crc32c;
use core::hash::{BuildHasher, Hasher};
#[test]
fn hasher_default() {
let hasher = CRC32CHasher::default();
assert_eq!(hasher.finish(), 0);
}
#[test]
fn hasher_with_seed() {
let hasher = CRC32CHasher::with_seed(0x9B9BEFFB);
assert_eq!(hasher.finish(), 0x9B9BEFFB);
}
#[test]
fn build_hasher() {
let build_hasher = CRC32CHasher::default();
let mut hasher = build_hasher.build_hasher();
hasher.write(b"abcdefghijklmnopqrstuvwxyz");
assert_eq!(hasher.finish(), 0x9EE6EF25);
}
#[test]
fn build_hasher_results_are_coherent_with_free_function() {
let build_hasher = CRC32CHasher::default();
let mut hasher = build_hasher.build_hasher();
const HASH_ME: &[u8] = b"abcdefghijklmnopqrstuvwxyz";
let hash_free_function = crc32c::slice_by_8(HASH_ME);
hasher.write(HASH_ME);
assert_eq!(hasher.finish(), hash_free_function as u64);
let hash_free_function = crc32c::slice_by_8_with_seed(HASH_ME, hash_free_function);
hasher.write(HASH_ME);
assert_eq!(hasher.finish(), hash_free_function as u64);
}
#[test]
fn hasher_is_usable_in_std_collections() {
extern crate std;
use std::collections::HashMap;
const HASH_ME: &str = "hash me!";
const VALUE: &str = "Hi";
let mut map = HashMap::with_hasher(CRC32CBuildHasher::default());
map.insert(HASH_ME, VALUE);
assert_eq!(map.get(&HASH_ME), Some(&VALUE));
}
}