pub const GLOBAL_EVICTION_HASH: u64 = 0;
#[expect(
clippy::unwrap_used,
reason = "blake3 always returns 32 bytes; [..8] into [u8; 8] cannot fail"
)]
pub fn hash_node_path(path: &str) -> u64 {
let hash = blake3::hash(path.as_bytes());
let h = u64::from_le_bytes(hash.as_bytes()[..8].try_into().unwrap());
if h == GLOBAL_EVICTION_HASH {
1
} else {
h
}
}
#[expect(
clippy::unwrap_used,
reason = "blake3 always returns 32 bytes; [..8] into [u8; 8] cannot fail"
)]
pub fn hash_token_path(tokens: &[u32]) -> u64 {
let mut hasher = blake3::Hasher::new();
for t in tokens {
hasher.update(&t.to_le_bytes());
}
let hash = hasher.finalize();
let h = u64::from_le_bytes(hash.as_bytes()[..8].try_into().unwrap());
if h == GLOBAL_EVICTION_HASH {
1
} else {
h
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn hash_node_path_never_returns_sentinel() {
for s in ["", "a", "hello world", "/api/v1/chat/completions"] {
assert_ne!(hash_node_path(s), GLOBAL_EVICTION_HASH);
}
}
#[test]
fn hash_token_path_never_returns_sentinel() {
for tokens in [&[][..], &[1][..], &[1, 2, 3][..], &[0; 32][..]] {
assert_ne!(hash_token_path(tokens), GLOBAL_EVICTION_HASH);
}
}
#[test]
fn hash_is_deterministic() {
assert_eq!(hash_node_path("a"), hash_node_path("a"));
assert_eq!(hash_token_path(&[1, 2, 3]), hash_token_path(&[1, 2, 3]));
}
#[test]
fn hash_token_path_matches_concat_then_hash() {
for tokens in [&[][..], &[42][..], &[1, 2, 3, 4][..], &[0u32; 64][..]] {
let concat: Vec<u8> = tokens.iter().flat_map(|t| t.to_le_bytes()).collect();
let expected_full = blake3::hash(&concat);
let expected = u64::from_le_bytes(expected_full.as_bytes()[..8].try_into().unwrap());
let expected = if expected == GLOBAL_EVICTION_HASH {
1
} else {
expected
};
assert_eq!(hash_token_path(tokens), expected);
}
}
}