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