1use alloc::string::String;
4use alloc::vec::Vec;
5
6use crate::value::JsonValue;
7
8pub fn to_compact_string(value: &JsonValue) -> String {
15 let mut out = String::new();
16 write_value(&mut out, value);
17 out
18}
19
20pub fn to_compact_vec(value: &JsonValue) -> Vec<u8> {
22 to_compact_string(value).into_bytes()
23}
24
25fn write_value(out: &mut String, value: &JsonValue) {
26 match value {
27 JsonValue::Null => out.push_str("null"),
28 JsonValue::Bool(true) => out.push_str("true"),
29 JsonValue::Bool(false) => out.push_str("false"),
30 JsonValue::Number(number) => out.push_str(number.as_str()),
31 JsonValue::String(string) => write_escaped(out, string),
32 JsonValue::Array(items) => {
33 out.push('[');
34 for (index, item) in items.iter().enumerate() {
35 if index > 0 {
36 out.push(',');
37 }
38 write_value(out, item);
39 }
40 out.push(']');
41 }
42 JsonValue::Object(object) => {
43 out.push('{');
44 for (index, member) in object.iter().enumerate() {
45 if index > 0 {
46 out.push(',');
47 }
48 write_escaped(out, member.key());
49 out.push(':');
50 write_value(out, member.value());
51 }
52 out.push('}');
53 }
54 }
55}
56
57pub(crate) fn write_escaped(out: &mut String, s: &str) {
58 out.push('"');
59 for c in s.chars() {
60 match c {
61 '"' => out.push_str("\\\""),
62 '\\' => out.push_str("\\\\"),
63 '\u{08}' => out.push_str("\\b"),
64 '\u{0C}' => out.push_str("\\f"),
65 '\n' => out.push_str("\\n"),
66 '\r' => out.push_str("\\r"),
67 '\t' => out.push_str("\\t"),
68 c if (c as u32) < 0x20 => {
69 out.push_str("\\u");
70 let code = c as u32;
71 for shift in [12u32, 8, 4, 0] {
72 let nibble = ((code >> shift) & 0xF) as u8;
73 let hex = if nibble < 10 {
74 b'0' + nibble
75 } else {
76 b'a' + nibble - 10
77 };
78 out.push(hex as char);
79 }
80 }
81 c => out.push(c),
82 }
83 }
84 out.push('"');
85}