use serde_json::Value;
pub fn canonical_json(value: &Value) -> String {
let mut out = String::new();
write_canonical(value, &mut out);
out
}
pub fn write_canonical(value: &Value, out: &mut String) {
match value {
Value::Null => out.push_str("null"),
Value::Bool(b) => out.push_str(if *b { "true" } else { "false" }),
Value::Number(n) => out.push_str(&n.to_string()),
Value::String(s) => {
out.push_str(&serde_json::to_string(s).unwrap_or_else(|_| "\"\"".to_string()))
}
Value::Array(items) => {
out.push('[');
for (index, item) in items.iter().enumerate() {
if index > 0 {
out.push(',');
}
write_canonical(item, out);
}
out.push(']');
}
Value::Object(map) => {
let mut keys: Vec<&String> = map.keys().collect();
keys.sort();
out.push('{');
for (index, key) in keys.iter().enumerate() {
if index > 0 {
out.push(',');
}
out.push_str(&serde_json::to_string(key).unwrap_or_else(|_| "\"\"".to_string()));
out.push(':');
if let Some(value) = map.get(*key) {
write_canonical(value, out);
}
}
out.push('}');
}
}
}
pub fn blake3_hex(bytes: &[u8]) -> String {
blake3::hash(bytes).to_hex().to_string()
}