nodedb_types/json_msgpack/
transcoder.rs1use std::fmt::Write as _;
8
9use super::reader::{Cursor, base64_encode};
10
11pub fn msgpack_to_json_string(bytes: &[u8]) -> zerompk::Result<String> {
13 if bytes.is_empty() {
14 return Ok(String::new());
15 }
16 let mut c = Cursor::new(bytes);
17 let mut out = String::with_capacity(bytes.len() * 2);
18 transcode_value(&mut c, &mut out)?;
19 Ok(out)
20}
21
22fn transcode_value(c: &mut Cursor<'_>, out: &mut String) -> zerompk::Result<()> {
23 if c.depth > 500 {
24 return Err(zerompk::Error::DepthLimitExceeded { max: 500 });
25 }
26
27 let marker = c.take()?;
28 match marker {
29 0xC0 => out.push_str("null"),
30 0xC2 => out.push_str("false"),
31 0xC3 => out.push_str("true"),
32
33 0x00..=0x7F => {
34 write_int(out, marker as i64);
35 }
36 0xE0..=0xFF => {
37 write_int(out, marker as i8 as i64);
38 }
39
40 0xCC => {
41 write_uint(out, c.take()? as u64);
42 }
43 0xCD => {
44 write_uint(out, c.read_u16_be()? as u64);
45 }
46 0xCE => {
47 write_uint(out, c.read_u32_be()? as u64);
48 }
49 0xCF => {
50 let b = c.take_n(8)?;
51 write_uint(
52 out,
53 u64::from_be_bytes([b[0], b[1], b[2], b[3], b[4], b[5], b[6], b[7]]),
54 );
55 }
56
57 0xD0 => {
58 write_int(out, c.take()? as i8 as i64);
59 }
60 0xD1 => {
61 let b = c.take_n(2)?;
62 write_int(out, i16::from_be_bytes([b[0], b[1]]) as i64);
63 }
64 0xD2 => {
65 let b = c.take_n(4)?;
66 write_int(out, i32::from_be_bytes([b[0], b[1], b[2], b[3]]) as i64);
67 }
68 0xD3 => {
69 let b = c.take_n(8)?;
70 write_int(
71 out,
72 i64::from_be_bytes([b[0], b[1], b[2], b[3], b[4], b[5], b[6], b[7]]),
73 );
74 }
75
76 0xCA => {
77 let b = c.take_n(4)?;
78 write_float(out, f32::from_be_bytes([b[0], b[1], b[2], b[3]]) as f64);
79 }
80 0xCB => {
81 let b = c.take_n(8)?;
82 write_float(
83 out,
84 f64::from_be_bytes([b[0], b[1], b[2], b[3], b[4], b[5], b[6], b[7]]),
85 );
86 }
87
88 m @ 0xA0..=0xBF => transcode_str(c, out, (m & 0x1F) as usize)?,
89 0xD9 => {
90 let l = c.take()? as usize;
91 transcode_str(c, out, l)?;
92 }
93 0xDA => {
94 let l = c.read_u16_be()? as usize;
95 transcode_str(c, out, l)?;
96 }
97 0xDB => {
98 let l = c.read_u32_be()? as usize;
99 transcode_str(c, out, l)?;
100 }
101
102 0xC4 => {
103 let l = c.take()? as usize;
104 transcode_bin(c, out, l)?;
105 }
106 0xC5 => {
107 let l = c.read_u16_be()? as usize;
108 transcode_bin(c, out, l)?;
109 }
110 0xC6 => {
111 let l = c.read_u32_be()? as usize;
112 transcode_bin(c, out, l)?;
113 }
114
115 m @ 0x90..=0x9F => transcode_array(c, out, (m & 0x0F) as usize)?,
116 0xDC => {
117 let l = c.read_u16_be()? as usize;
118 transcode_array(c, out, l)?;
119 }
120 0xDD => {
121 let l = c.read_u32_be()? as usize;
122 transcode_array(c, out, l)?;
123 }
124
125 m @ 0x80..=0x8F => transcode_map(c, out, (m & 0x0F) as usize)?,
126 0xDE => {
127 let l = c.read_u16_be()? as usize;
128 transcode_map(c, out, l)?;
129 }
130 0xDF => {
131 let l = c.read_u32_be()? as usize;
132 transcode_map(c, out, l)?;
133 }
134
135 0xD4 => {
137 c.take_n(2)?;
138 out.push_str("null");
139 }
140 0xD5 => {
141 c.take_n(3)?;
142 out.push_str("null");
143 }
144 0xD6 => {
145 c.take_n(5)?;
146 out.push_str("null");
147 }
148 0xD7 => {
149 c.take_n(9)?;
150 out.push_str("null");
151 }
152 0xD8 => {
153 c.take_n(17)?;
154 out.push_str("null");
155 }
156 0xC7 => {
157 let l = c.take()? as usize;
158 c.take_n(1 + l)?;
159 out.push_str("null");
160 }
161 0xC8 => {
162 let l = c.read_u16_be()? as usize;
163 c.take_n(1 + l)?;
164 out.push_str("null");
165 }
166 0xC9 => {
167 let l = c.read_u32_be()? as usize;
168 c.take_n(1 + l)?;
169 out.push_str("null");
170 }
171
172 _ => return Err(zerompk::Error::InvalidMarker(marker)),
173 }
174 Ok(())
175}
176
177fn write_int(out: &mut String, v: i64) {
178 let _ = write!(out, "{v}");
179}
180
181fn write_uint(out: &mut String, v: u64) {
182 let _ = write!(out, "{v}");
183}
184
185fn write_float(out: &mut String, v: f64) {
186 if v.is_nan() || v.is_infinite() {
187 out.push_str("null");
188 } else if v.fract() == 0.0 && v.abs() < (1i64 << 53) as f64 {
189 let _ = write!(out, "{v:.1}");
190 } else {
191 let _ = write!(out, "{v}");
192 }
193}
194
195fn transcode_str(c: &mut Cursor<'_>, out: &mut String, len: usize) -> zerompk::Result<()> {
196 let bytes = c.take_n(len)?;
197 let s = std::str::from_utf8(bytes).map_err(|_| zerompk::Error::InvalidMarker(0))?;
198 out.push('"');
199 for ch in s.chars() {
200 match ch {
201 '"' => out.push_str("\\\""),
202 '\\' => out.push_str("\\\\"),
203 '\n' => out.push_str("\\n"),
204 '\r' => out.push_str("\\r"),
205 '\t' => out.push_str("\\t"),
206 c if c < '\x20' => {
207 let _ = write!(out, "\\u{:04x}", c as u32);
208 }
209 c => out.push(c),
210 }
211 }
212 out.push('"');
213 Ok(())
214}
215
216fn transcode_bin(c: &mut Cursor<'_>, out: &mut String, len: usize) -> zerompk::Result<()> {
217 let bytes = c.take_n(len)?;
218 out.push('"');
219 out.push_str(&base64_encode(bytes));
220 out.push('"');
221 Ok(())
222}
223
224fn transcode_array(c: &mut Cursor<'_>, out: &mut String, len: usize) -> zerompk::Result<()> {
225 c.depth += 1;
226 out.push('[');
227 for i in 0..len {
228 if i > 0 {
229 out.push(',');
230 }
231 transcode_value(c, out)?;
232 }
233 out.push(']');
234 c.depth -= 1;
235 Ok(())
236}
237
238fn transcode_map(c: &mut Cursor<'_>, out: &mut String, len: usize) -> zerompk::Result<()> {
239 c.depth += 1;
240 out.push('{');
241 for i in 0..len {
242 if i > 0 {
243 out.push(',');
244 }
245 let key_marker = c.peek()?;
246 if (0xA0..=0xBF).contains(&key_marker)
247 || key_marker == 0xD9
248 || key_marker == 0xDA
249 || key_marker == 0xDB
250 {
251 transcode_value(c, out)?;
252 } else {
253 let mut tmp = String::new();
254 transcode_value(c, &mut tmp)?;
255 out.push('"');
256 out.push_str(&tmp);
257 out.push('"');
258 }
259 out.push(':');
260 transcode_value(c, out)?;
261 }
262 out.push('}');
263 c.depth -= 1;
264 Ok(())
265}
266
267#[cfg(test)]
268mod tests {
269 use super::*;
270 use crate::json_msgpack::writer::json_to_msgpack;
271
272 #[test]
273 fn basic_map() {
274 let val = serde_json::json!({"name": "alice", "age": 30, "active": true});
275 let mp = json_to_msgpack(&val).unwrap();
276 let json_str = msgpack_to_json_string(&mp).unwrap();
277 let parsed: serde_json::Value = serde_json::from_str(&json_str).unwrap();
278 assert_eq!(parsed["name"], "alice");
279 assert_eq!(parsed["age"], 30);
280 assert_eq!(parsed["active"], true);
281 }
282
283 #[test]
284 fn array() {
285 let val = serde_json::json!([1, "two", null, false]);
286 let mp = json_to_msgpack(&val).unwrap();
287 let json_str = msgpack_to_json_string(&mp).unwrap();
288 let parsed: serde_json::Value = serde_json::from_str(&json_str).unwrap();
289 assert_eq!(parsed, val);
290 }
291
292 #[test]
293 fn escaping() {
294 let val = serde_json::json!({"msg": "hello \"world\"\nnewline"});
295 let mp = json_to_msgpack(&val).unwrap();
296 let json_str = msgpack_to_json_string(&mp).unwrap();
297 let parsed: serde_json::Value = serde_json::from_str(&json_str).unwrap();
298 assert_eq!(parsed["msg"], "hello \"world\"\nnewline");
299 }
300
301 #[test]
302 fn empty() {
303 assert_eq!(msgpack_to_json_string(&[]).unwrap(), "");
304 }
305
306 #[test]
307 fn nested() {
308 let val = serde_json::json!({"a": {"b": [1, 2, {"c": 3}]}});
309 let mp = json_to_msgpack(&val).unwrap();
310 let json_str = msgpack_to_json_string(&mp).unwrap();
311 let parsed: serde_json::Value = serde_json::from_str(&json_str).unwrap();
312 assert_eq!(parsed, val);
313 }
314}