1pub fn canonical_json(value: &serde_json::Value) -> Vec<u8> {
21 let mut out = Vec::new();
22 write_canonical(&mut out, value);
23 out
24}
25
26pub fn canonical_json_for<T: serde::Serialize>(value: &T) -> Vec<u8> {
30 let v: serde_json::Value =
31 serde_json::to_value(value).expect("Serialize → Value should not fail for our types");
32 canonical_json(&v)
33}
34
35fn write_canonical(out: &mut Vec<u8>, v: &serde_json::Value) {
36 use serde_json::Value;
37 match v {
38 Value::Null => out.extend_from_slice(b"null"),
39 Value::Bool(b) => out.extend_from_slice(if *b { b"true" } else { b"false" }),
40 Value::Number(n) => out.extend_from_slice(n.to_string().as_bytes()),
41 Value::String(s) => {
42 let escaped = serde_json::to_string(s).expect("string serialization is infallible");
43 out.extend_from_slice(escaped.as_bytes());
44 }
45 Value::Array(arr) => {
46 out.push(b'[');
47 for (i, item) in arr.iter().enumerate() {
48 if i > 0 {
49 out.push(b',');
50 }
51 write_canonical(out, item);
52 }
53 out.push(b']');
54 }
55 Value::Object(map) => {
56 let mut keys: Vec<&String> = map.keys().collect();
58 keys.sort();
59 out.push(b'{');
60 for (i, k) in keys.iter().enumerate() {
61 if i > 0 {
62 out.push(b',');
63 }
64 let kesc = serde_json::to_string(k).expect("string serialization is infallible");
65 out.extend_from_slice(kesc.as_bytes());
66 out.push(b':');
67 write_canonical(out, &map[*k]);
68 }
69 out.push(b'}');
70 }
71 }
72}
73
74#[cfg(test)]
75mod tests {
76 use super::*;
77 use serde_json::json;
78
79 #[test]
80 fn primitives_roundtrip() {
81 assert_eq!(canonical_json(&json!(null)), b"null");
82 assert_eq!(canonical_json(&json!(true)), b"true");
83 assert_eq!(canonical_json(&json!(false)), b"false");
84 assert_eq!(canonical_json(&json!(42)), b"42");
85 assert_eq!(canonical_json(&json!(0.5)), b"0.5");
86 assert_eq!(canonical_json(&json!("hi")), br#""hi""#);
87 }
88
89 #[test]
90 fn object_keys_are_sorted() {
91 let v = json!({"b": 1, "a": 2, "c": 3});
92 assert_eq!(canonical_json(&v), br#"{"a":2,"b":1,"c":3}"#);
93 }
94
95 #[test]
96 fn nested_objects_recursively_sorted() {
97 let v = json!({"x": {"b": 1, "a": 2}, "a": {"y": 1, "x": 2}});
98 let want = br#"{"a":{"x":2,"y":1},"x":{"a":2,"b":1}}"#;
99 assert_eq!(canonical_json(&v), want);
100 }
101
102 #[test]
103 fn arrays_preserve_order() {
104 let v = json!([3, 1, 2]);
105 assert_eq!(canonical_json(&v), b"[3,1,2]");
106 }
107
108 #[test]
109 fn whitespace_stripped() {
110 let v: serde_json::Value =
113 serde_json::from_str(r#" { "a" : 1 , "b" : [ 2 , 3 ] } "#).unwrap();
114 assert_eq!(canonical_json(&v), br#"{"a":1,"b":[2,3]}"#);
115 }
116
117 #[test]
118 fn key_order_is_independent_of_insertion_order() {
119 let a: serde_json::Value = serde_json::from_str(r#"{"a":1,"b":2}"#).unwrap();
120 let b: serde_json::Value = serde_json::from_str(r#"{"b":2,"a":1}"#).unwrap();
121 assert_eq!(canonical_json(&a), canonical_json(&b));
122 }
123
124 #[test]
125 fn canonical_json_for_typed_value() {
126 #[derive(serde::Serialize)]
127 struct Probe {
128 tools: Vec<&'static str>,
129 version: u32,
130 }
131 let p = Probe {
132 tools: vec!["a", "b"],
133 version: 1,
134 };
135 assert_eq!(
138 canonical_json_for(&p),
139 br#"{"tools":["a","b"],"version":1}"#
140 );
141 }
142}