use serde::Serialize;
pub fn to_jcs(value: &serde_json::Value) -> Vec<u8> {
serde_jcs::to_vec(value).expect("JCS serialization is infallible for valid JSON")
}
pub fn to_jcs_for<T: Serialize>(value: &T) -> Vec<u8> {
serde_jcs::to_vec(value).expect("JCS serialization should not fail for valid types")
}
pub fn jcs_sha256(value: &serde_json::Value) -> String {
use sha2::Digest;
let bytes = to_jcs(value);
format!("{:x}", sha2::Sha256::digest(&bytes))
}
#[cfg(test)]
mod tests {
use super::*;
use serde_json::json;
#[test]
fn scientific_notation_is_expanded() {
let v = json!(1e10);
let out = String::from_utf8(to_jcs(&v)).unwrap();
assert_eq!(out, "10000000000");
}
#[test]
fn trailing_zeros_removed() {
let v = json!(1.0);
let out = String::from_utf8(to_jcs(&v)).unwrap();
assert_eq!(out, "1");
}
#[test]
fn very_small_number_no_scientific() {
let v = json!(0.00001);
let out = String::from_utf8(to_jcs(&v)).unwrap();
assert!(
!out.contains('e') && !out.contains('E'),
"expected no scientific notation, got: {out}"
);
}
#[test]
fn keys_sorted_lexicographically() {
let v = json!({"z": 1, "a": 2, "m": 3});
let out = String::from_utf8(to_jcs(&v)).unwrap();
assert_eq!(out, r#"{"a":2,"m":3,"z":1}"#);
}
#[test]
fn nested_keys_sorted_recursively() {
let v = json!({"b": {"z": 1, "a": 2}, "a": 1});
let out = String::from_utf8(to_jcs(&v)).unwrap();
assert_eq!(out, r#"{"a":1,"b":{"a":2,"z":1}}"#);
}
#[test]
fn boolean_and_null_preserved() {
assert_eq!(String::from_utf8(to_jcs(&json!(true))).unwrap(), "true");
assert_eq!(String::from_utf8(to_jcs(&json!(null))).unwrap(), "null");
}
#[test]
fn deterministic_across_insertion_order() {
let a: serde_json::Value = serde_json::from_str(r#"{"b":1,"a":2}"#).unwrap();
let b: serde_json::Value = serde_json::from_str(r#"{"a":2,"b":1}"#).unwrap();
assert_eq!(to_jcs(&a), to_jcs(&b));
}
}