indexbus_inspect/internal/
json.rs

1use crate::internal::inspect::{Report, WakeInfo};
2
3fn escape_json_str(s: &str) -> String {
4    let mut out = String::with_capacity(s.len() + 8);
5    for ch in s.chars() {
6        match ch {
7            '"' => out.push_str("\\\""),
8            '\\' => out.push_str("\\\\"),
9            '\n' => out.push_str("\\n"),
10            '\r' => out.push_str("\\r"),
11            '\t' => out.push_str("\\t"),
12            c if c.is_control() => {
13                use core::fmt::Write;
14                let _ = write!(out, "\\u{:04x}", c as u32);
15            }
16            c => out.push(c),
17        }
18    }
19    out
20}
21
22fn write_kv_str(out: &mut String, k: &str, v: &str) {
23    out.push('"');
24    out.push_str(k);
25    out.push_str("\":\"");
26    out.push_str(&escape_json_str(v));
27    out.push('"');
28}
29
30fn write_kv_u64(out: &mut String, k: &str, v: u64) {
31    use core::fmt::Write;
32    out.push('"');
33    out.push_str(k);
34    out.push_str("\":");
35    let _ = write!(out, "{v}");
36}
37
38fn write_kv_u32(out: &mut String, k: &str, v: u32) {
39    write_kv_u64(out, k, v as u64);
40}
41
42fn write_wake(out: &mut String, wake: &WakeInfo) {
43    out.push_str("\"wake\":{");
44    write_kv_u64(out, "offset", wake.offset as u64);
45    out.push(',');
46    write_kv_u64(out, "size", wake.size as u64);
47    out.push(',');
48    out.push_str("\"present\":");
49    out.push_str(if wake.present { "true" } else { "false" });
50    out.push('}');
51}
52
53pub(crate) fn to_json(report: &Report) -> String {
54    let mut out = String::with_capacity(512);
55    out.push('{');
56
57    write_kv_str(&mut out, "path", &report.path);
58    out.push(',');
59
60    write_kv_str(&mut out, "kind", report.kind);
61    out.push(',');
62
63    write_kv_u32(&mut out, "magic", report.header_magic);
64    out.push(',');
65    write_kv_u32(&mut out, "version", report.header_version as u32);
66    out.push(',');
67    write_kv_u32(&mut out, "flags", report.header_flags as u32);
68    out.push(',');
69    write_kv_u32(&mut out, "capabilities", report.capabilities);
70    out.push(',');
71    write_kv_u32(&mut out, "layout_bytes", report.layout_bytes);
72    out.push(',');
73    write_kv_u64(&mut out, "mapped_bytes", report.mapped_bytes as u64);
74    out.push(',');
75    write_kv_u64(&mut out, "base_size", report.base_size as u64);
76    out.push(',');
77
78    out.push_str("\"cap_names\":[");
79    for (i, n) in report.cap_names.iter().enumerate() {
80        if i != 0 {
81            out.push(',');
82        }
83        out.push('"');
84        out.push_str(n);
85        out.push('"');
86    }
87    out.push_str("],");
88
89    match report.initialized {
90        Some(v) => {
91            write_kv_u32(&mut out, "initialized", v);
92            out.push(',');
93        }
94        None => {
95            out.push_str("\"initialized\":null,");
96        }
97    }
98
99    if let Some(wake) = &report.wake {
100        write_wake(&mut out, wake);
101        out.push(',');
102    } else {
103        out.push_str("\"wake\":null,");
104    }
105
106    out.push_str("\"offsets\":[");
107    for (i, (name, off)) in report.offsets.iter().enumerate() {
108        if i != 0 {
109            out.push(',');
110        }
111        out.push('{');
112        write_kv_str(&mut out, "name", name);
113        out.push(',');
114        write_kv_u64(&mut out, "offset", *off as u64);
115        out.push('}');
116    }
117    out.push(']');
118
119    out.push_str(",\"values\":[");
120    for (i, (name, val)) in report.values.iter().enumerate() {
121        if i != 0 {
122            out.push(',');
123        }
124        out.push('{');
125        write_kv_str(&mut out, "name", name);
126        out.push(',');
127        write_kv_str(&mut out, "value", val);
128        out.push('}');
129    }
130    out.push(']');
131
132    out.push('}');
133    out
134}