supercode_interchange/orchestration/codec/
canonical.rs1use serde_json::{Map, Value};
7
8pub fn sort_keys(value: &Value) -> Value {
10 match value {
11 Value::Array(items) => Value::Array(items.iter().map(sort_keys).collect()),
12 Value::Object(object) => {
13 let mut keys: Vec<&String> = object.keys().collect();
14 keys.sort();
15 let mut out = Map::new();
16 for key in keys {
17 out.insert(key.clone(), sort_keys(&object[key]));
18 }
19 Value::Object(out)
20 }
21 other => other.clone(),
22 }
23}
24
25pub fn canonical_json(value: &Value) -> String {
27 let sorted = sort_keys(value);
28 let mut text = pretty(&sorted, 0);
29 text.push('\n');
30 text
31}
32
33fn pretty(value: &Value, depth: usize) -> String {
35 let pad = |d: usize| " ".repeat(d);
36 match value {
37 Value::Array(items) if items.is_empty() => "[]".into(),
38 Value::Array(items) => {
39 let inner: Vec<String> = items
40 .iter()
41 .map(|v| format!("{}{}", pad(depth + 1), pretty(v, depth + 1)))
42 .collect();
43 format!("[\n{}\n{}]", inner.join(",\n"), pad(depth))
44 }
45 Value::Object(object) if object.is_empty() => "{}".into(),
46 Value::Object(object) => {
47 let mut keys: Vec<&String> = object.keys().collect();
48 keys.sort();
49 let inner: Vec<String> = keys
50 .into_iter()
51 .map(|k| {
52 format!(
53 "{}{}: {}",
54 pad(depth + 1),
55 serde_json::to_string(k).unwrap(),
56 pretty(&object[k], depth + 1)
57 )
58 })
59 .collect();
60 format!("{{\n{}\n{}}}", inner.join(",\n"), pad(depth))
61 }
62 Value::Number(n) => json_number(n),
63 other => serde_json::to_string(other).unwrap(),
64 }
65}
66
67fn json_number(n: &serde_json::Number) -> String {
70 if let Some(f) = n.as_f64() {
71 if n.is_f64() && f.fract() == 0.0 && f.abs() < 1e21 {
72 return format!("{}", f as i64);
73 }
74 }
75 n.to_string()
76}