const FNV_OFFSET: u64 = 0xcbf2_9ce4_8422_2325;
const FNV_PRIME: u64 = 0x0000_0100_0000_01b3;
#[must_use]
pub fn stable_id(text: &str) -> u64 {
stable_id_bytes(text.as_bytes())
}
#[must_use]
pub fn stable_id_bytes(bytes: &[u8]) -> u64 {
bytes.iter().fold(FNV_OFFSET, |hash, &byte| {
(hash ^ u64::from(byte)).wrapping_mul(FNV_PRIME)
})
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn same_input_yields_same_id() {
assert_eq!(stable_id("hello"), stable_id("hello"));
}
#[test]
fn different_inputs_yield_different_ids() {
assert_ne!(stable_id("hello"), stable_id("world"));
}
#[test]
fn empty_string_yields_offset_basis() {
assert_eq!(stable_id(""), FNV_OFFSET);
}
#[test]
fn stable_id_bytes_agrees_with_stable_id_on_valid_utf8() {
assert_eq!(stable_id_bytes("hello".as_bytes()), stable_id("hello"));
}
#[test]
fn stable_id_bytes_hashes_non_utf8_bytes() {
let bytes = [0xFFu8, 0x00, 0x89, 0x50, 0x4E, 0x47];
assert_eq!(stable_id_bytes(&bytes), stable_id_bytes(&bytes));
assert_ne!(stable_id_bytes(&bytes), stable_id_bytes(&bytes[1..]));
}
}