1use serde::Serialize;
8
9pub fn to_jcs(value: &serde_json::Value) -> Vec<u8> {
11 serde_jcs::to_vec(value).expect("JCS serialization is infallible for valid JSON")
12}
13
14pub fn to_jcs_for<T: Serialize>(value: &T) -> Vec<u8> {
16 serde_jcs::to_vec(value).expect("JCS serialization should not fail for valid types")
17}
18
19pub fn jcs_sha256(value: &serde_json::Value) -> String {
21 use sha2::Digest;
22 let bytes = to_jcs(value);
23 format!("{:x}", sha2::Sha256::digest(&bytes))
24}
25
26#[cfg(test)]
27mod tests {
28 use super::*;
29 use serde_json::json;
30
31 #[test]
32 fn scientific_notation_is_expanded() {
33 let v = json!(1e10);
34 let out = String::from_utf8(to_jcs(&v)).unwrap();
35 assert_eq!(out, "10000000000");
36 }
37
38 #[test]
39 fn trailing_zeros_removed() {
40 let v = json!(1.0);
41 let out = String::from_utf8(to_jcs(&v)).unwrap();
42 assert_eq!(out, "1");
43 }
44
45 #[test]
46 fn very_small_number_no_scientific() {
47 let v = json!(0.00001);
48 let out = String::from_utf8(to_jcs(&v)).unwrap();
49 assert!(
50 !out.contains('e') && !out.contains('E'),
51 "expected no scientific notation, got: {out}"
52 );
53 }
54
55 #[test]
56 fn keys_sorted_lexicographically() {
57 let v = json!({"z": 1, "a": 2, "m": 3});
58 let out = String::from_utf8(to_jcs(&v)).unwrap();
59 assert_eq!(out, r#"{"a":2,"m":3,"z":1}"#);
60 }
61
62 #[test]
63 fn nested_keys_sorted_recursively() {
64 let v = json!({"b": {"z": 1, "a": 2}, "a": 1});
65 let out = String::from_utf8(to_jcs(&v)).unwrap();
66 assert_eq!(out, r#"{"a":1,"b":{"a":2,"z":1}}"#);
67 }
68
69 #[test]
70 fn boolean_and_null_preserved() {
71 assert_eq!(String::from_utf8(to_jcs(&json!(true))).unwrap(), "true");
72 assert_eq!(String::from_utf8(to_jcs(&json!(null))).unwrap(), "null");
73 }
74
75 #[test]
76 fn deterministic_across_insertion_order() {
77 let a: serde_json::Value = serde_json::from_str(r#"{"b":1,"a":2}"#).unwrap();
78 let b: serde_json::Value = serde_json::from_str(r#"{"a":2,"b":1}"#).unwrap();
79 assert_eq!(to_jcs(&a), to_jcs(&b));
80 }
81}