use crate::protocols::{BlockExtraInfo, BlockMmObjectInfo};
use super::types::ExtraKeyItem;
const DYNAMO_CACHE_SALT_PREFIX: &str = "dynamo-cache-salt:";
pub fn parse_mm_hash_from_extra_key(s: &str) -> Option<u64> {
if s.len() == 64 && s.chars().all(|c| c.is_ascii_hexdigit()) {
return u64::from_str_radix(&s[..16], 16).ok();
}
None
}
pub fn extra_keys_to_cache_namespace(
extra_keys: Option<&[Option<Vec<ExtraKeyItem>>]>,
lora_name: Option<&str>,
) -> Option<String> {
let first_block = extra_keys?.first()?.as_ref()?;
let mut unmatched_lora = lora_name.filter(|name| !name.is_empty());
first_block.iter().find_map(|key| {
let ExtraKeyItem::Hash(value) = key else {
return None;
};
if unmatched_lora.is_some_and(|name| name == value) {
unmatched_lora = None;
return None;
}
value
.strip_prefix(DYNAMO_CACHE_SALT_PREFIX)
.filter(|namespace| !namespace.is_empty())
.map(str::to_owned)
})
}
pub fn extra_keys_to_block_mm_infos(
extra_keys: Option<Vec<Option<Vec<ExtraKeyItem>>>>,
) -> Option<Vec<Option<BlockExtraInfo>>> {
let extra_keys = extra_keys?;
if extra_keys.is_empty() {
return None;
}
let infos: Vec<Option<BlockExtraInfo>> = extra_keys
.into_iter()
.map(|block_keys| {
let mm_objects: Vec<BlockMmObjectInfo> = block_keys
.unwrap_or_default()
.iter()
.filter_map(|key| match key {
ExtraKeyItem::Hash(hash)
| ExtraKeyItem::HashWithSignedOffset((hash, _))
| ExtraKeyItem::HashWithUnsignedOffset((hash, _)) => {
parse_mm_hash_from_extra_key(hash)
}
ExtraKeyItem::Bytes(_)
| ExtraKeyItem::Signed(_)
| ExtraKeyItem::Unsigned(_)
| ExtraKeyItem::Float(_)
| ExtraKeyItem::Bool(_) => None,
})
.map(|mm_hash| BlockMmObjectInfo {
mm_hash,
offsets: vec![],
})
.collect();
if mm_objects.is_empty() {
None
} else {
Some(BlockExtraInfo { mm_objects })
}
})
.collect();
if infos.iter().all(|i| i.is_none()) {
return None;
}
Some(infos)
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn prompt_embedding_bytes_are_not_cache_namespace() {
let extra_keys = [Some(vec![ExtraKeyItem::Bytes(b"prompt-embed".to_vec())])];
assert_eq!(extra_keys_to_cache_namespace(Some(&extra_keys), None), None);
}
#[test]
fn untagged_strings_are_not_cache_namespaces() {
let extra_keys = [Some(vec![ExtraKeyItem::Hash("tenant-a".to_string())])];
assert_eq!(extra_keys_to_cache_namespace(Some(&extra_keys), None), None);
}
#[test]
fn tagged_cache_namespace_is_decoded() {
let extra_keys = [Some(vec![ExtraKeyItem::Hash(
"dynamo-cache-salt:tenant-a".to_string(),
)])];
assert_eq!(
extra_keys_to_cache_namespace(Some(&extra_keys), None).as_deref(),
Some("tenant-a")
);
}
#[test]
fn cache_namespace_equal_to_lora_name_is_decoded() {
let extra_keys = [Some(vec![
ExtraKeyItem::Hash("adapter-a".to_string()),
ExtraKeyItem::Hash("dynamo-cache-salt:adapter-a".to_string()),
])];
assert_eq!(
extra_keys_to_cache_namespace(Some(&extra_keys), Some("adapter-a")).as_deref(),
Some("adapter-a")
);
}
}