const FNV_OFFSET: u64 = 0xcbf2_9ce4_8422_2325;
const FNV_PRIME: u64 = 0x0000_0100_0000_01b3;
fn fnv1a(salt: u8, segments: &[&[u8]]) -> u64 {
let mut hash = FNV_OFFSET;
hash ^= u64::from(salt);
hash = hash.wrapping_mul(FNV_PRIME);
for segment in segments {
for &byte in *segment {
hash ^= u64::from(byte);
hash = hash.wrapping_mul(FNV_PRIME);
}
}
hash
}
pub fn content_id(segments: &[&[u8]]) -> u128 {
(u128::from(fnv1a(0x4d, segments)) << 64) | u128::from(fnv1a(0xc7, segments))
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn given_the_same_segments_when_hashed_then_should_be_stable() {
let a = content_id(&[b"owner", &[1], b"body"]);
let b = content_id(&[b"owner", &[1], b"body"]);
assert_eq!(a, b);
}
#[test]
fn given_different_segments_when_hashed_then_should_differ() {
assert_ne!(content_id(&[b"a"]), content_id(&[b"b"]));
}
#[test]
fn given_the_pinned_memory_segments_when_hashed_then_should_match_the_golden_id() {
let id = content_id(&[&[0], b"agent", &[0], &[1], b"x"]);
let rendered = crate::agent::RecordId::from_u128(id).to_string();
assert_eq!(rendered, "1A9GVS6SJ6SNS4KY0H19130WCW");
}
}