use std::fmt::Write;
use sha2::{Digest, Sha256};
pub fn key_prefix(deployment_id: &str, weight_version: &str, draft_weight_version: &str) -> String {
let payload = format!(
"{{\"deployment_id\":{},\"draft_weight_version\":{},\"weight_version\":{}}}",
json_string(deployment_id),
json_string(draft_weight_version),
json_string(weight_version),
);
let digest = Sha256::digest(payload.as_bytes());
let mut prefix = String::with_capacity(5 + 2 * digest.len());
prefix.push_str("tsl3-");
for byte in digest {
write!(prefix, "{byte:02x}").expect("writing to a String");
}
prefix
}
pub fn object_key(
prefix: &str,
content_hash: &str,
group: u32,
page_offset: i32,
rank: i64,
) -> String {
format!("{prefix}_{content_hash}|g{group}|o{page_offset}|r{rank}|c0")
}
fn json_string(value: &str) -> String {
let mut out = String::with_capacity(value.len() + 2);
out.push('"');
for character in value.chars() {
match character {
'\\' => out.push_str("\\\\"),
'"' => out.push_str("\\\""),
'\u{8}' => out.push_str("\\b"),
'\u{c}' => out.push_str("\\f"),
'\n' => out.push_str("\\n"),
'\r' => out.push_str("\\r"),
'\t' => out.push_str("\\t"),
' '..='~' => out.push(character),
_ => {
let mut units = [0_u16; 2];
for unit in character.encode_utf16(&mut units) {
write!(out, "\\u{unit:04x}").expect("writing to a String");
}
}
}
}
out.push('"');
out
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn json_strings_escape_as_python_does() {
assert_eq!(json_string("v1"), "\"v1\"");
assert_eq!(json_string("a\"b\\c"), "\"a\\\"b\\\\c\"");
assert_eq!(json_string("\t\n\u{1}\u{7f}"), "\"\\t\\n\\u0001\\u007f\"");
assert_eq!(json_string("é😀"), "\"\\u00e9\\ud83d\\ude00\"");
}
#[test]
fn prefixes_match_the_python_namespaces() {
assert_eq!(
key_prefix("0123abcd", "default", ""),
"tsl3-25bbe86d95ca1c75d7cf2b311774d571c684bd9d967e2ef25bd4769e392ebb98"
);
let version = "v2-é😀\"x";
assert_eq!(
key_prefix("dep", version, version),
"tsl3-8dcc778934a5e4e3e9613e82643df0983bad543e9389867a447724f741566223"
);
}
#[test]
fn target_and_draft_weight_versions_name_their_own_namespaces() {
let base = key_prefix("dep", "v1", "draft-v1");
let target = key_prefix("dep", "v2", "draft-v1");
let draft = key_prefix("dep", "v1", "draft-v2");
assert!(base != target && base != draft && target != draft);
assert_ne!(key_prefix("dep", "v1", ""), key_prefix("dep", "v1", "v1"));
}
#[test]
fn object_keys_name_the_shard() {
assert_eq!(
object_key("tsl3-ab", "f00d", 2, 1, 3),
"tsl3-ab_f00d|g2|o1|r3|c0"
);
}
}