Skip to main content

nodedb_types/json_msgpack/
reader.rs

1// SPDX-License-Identifier: Apache-2.0
2
3//! Cursor-based msgpack → `serde_json::Value` and `nodedb_types::Value` readers.
4//!
5//! Deterministic raw byte parser — the first byte of each msgpack value
6//! unambiguously identifies its type per the msgpack specification.
7
8pub(crate) struct Cursor<'a> {
9    pub(crate) data: &'a [u8],
10    pub(crate) pos: usize,
11    pub(crate) depth: usize,
12}
13
14impl<'a> Cursor<'a> {
15    pub(crate) fn new(data: &'a [u8]) -> Self {
16        Self {
17            data,
18            pos: 0,
19            depth: 0,
20        }
21    }
22
23    #[inline]
24    pub(crate) fn peek(&self) -> zerompk::Result<u8> {
25        self.data
26            .get(self.pos)
27            .copied()
28            .ok_or(zerompk::Error::BufferTooSmall)
29    }
30
31    #[inline]
32    pub(crate) fn take(&mut self) -> zerompk::Result<u8> {
33        let b = self.peek()?;
34        self.pos += 1;
35        Ok(b)
36    }
37
38    #[inline]
39    pub(crate) fn take_n(&mut self, n: usize) -> zerompk::Result<&'a [u8]> {
40        if self.pos + n > self.data.len() {
41            return Err(zerompk::Error::BufferTooSmall);
42        }
43        let slice = &self.data[self.pos..self.pos + n];
44        self.pos += n;
45        Ok(slice)
46    }
47
48    pub(crate) fn read_u16_be(&mut self) -> zerompk::Result<u16> {
49        let b = self.take_n(2)?;
50        Ok(u16::from_be_bytes([b[0], b[1]]))
51    }
52
53    pub(crate) fn read_u32_be(&mut self) -> zerompk::Result<u32> {
54        let b = self.take_n(4)?;
55        Ok(u32::from_be_bytes([b[0], b[1], b[2], b[3]]))
56    }
57}
58
59/// Deserialize a `serde_json::Value` from MessagePack bytes.
60pub fn json_from_msgpack(bytes: &[u8]) -> zerompk::Result<serde_json::Value> {
61    let mut cursor = Cursor::new(bytes);
62    read_json_value(&mut cursor)
63}
64
65/// Deserialize a `nodedb_types::Value` from standard MessagePack bytes.
66pub fn value_from_msgpack(bytes: &[u8]) -> zerompk::Result<crate::Value> {
67    let mut cursor = Cursor::new(bytes);
68    read_native_value(&mut cursor)
69}
70
71// ── JSON value reader ──
72
73fn read_json_value(c: &mut Cursor<'_>) -> zerompk::Result<serde_json::Value> {
74    if c.depth > 500 {
75        return Err(zerompk::Error::DepthLimitExceeded { max: 500 });
76    }
77
78    let marker = c.take()?;
79    match marker {
80        0xC0 => Ok(serde_json::Value::Null),
81        0xC2 => Ok(serde_json::Value::Bool(false)),
82        0xC3 => Ok(serde_json::Value::Bool(true)),
83
84        0x00..=0x7F => Ok(serde_json::Value::Number((marker as i64).into())),
85        0xE0..=0xFF => Ok(serde_json::Value::Number((marker as i8 as i64).into())),
86
87        0xCC => Ok(serde_json::Value::Number(c.take()?.into())),
88        0xCD => Ok(serde_json::Value::Number(c.read_u16_be()?.into())),
89        0xCE => Ok(serde_json::Value::Number(c.read_u32_be()?.into())),
90        0xCF => {
91            let b = c.take_n(8)?;
92            let v = u64::from_be_bytes([b[0], b[1], b[2], b[3], b[4], b[5], b[6], b[7]]);
93            Ok(serde_json::Value::Number(v.into()))
94        }
95
96        0xD0 => Ok(serde_json::Value::Number((c.take()? as i8 as i64).into())),
97        0xD1 => {
98            let b = c.take_n(2)?;
99            Ok(serde_json::Value::Number(
100                (i16::from_be_bytes([b[0], b[1]]) as i64).into(),
101            ))
102        }
103        0xD2 => {
104            let b = c.take_n(4)?;
105            Ok(serde_json::Value::Number(
106                (i32::from_be_bytes([b[0], b[1], b[2], b[3]]) as i64).into(),
107            ))
108        }
109        0xD3 => {
110            let b = c.take_n(8)?;
111            Ok(serde_json::Value::Number(
112                i64::from_be_bytes([b[0], b[1], b[2], b[3], b[4], b[5], b[6], b[7]]).into(),
113            ))
114        }
115
116        0xCA => {
117            let b = c.take_n(4)?;
118            Ok(serde_json::json!(
119                f32::from_be_bytes([b[0], b[1], b[2], b[3]]) as f64
120            ))
121        }
122        0xCB => {
123            let b = c.take_n(8)?;
124            Ok(serde_json::json!(f64::from_be_bytes([
125                b[0], b[1], b[2], b[3], b[4], b[5], b[6], b[7]
126            ])))
127        }
128
129        m @ 0xA0..=0xBF => read_json_str(c, (m & 0x1F) as usize),
130        0xD9 => {
131            let l = c.take()? as usize;
132            read_json_str(c, l)
133        }
134        0xDA => {
135            let l = c.read_u16_be()? as usize;
136            read_json_str(c, l)
137        }
138        0xDB => {
139            let l = c.read_u32_be()? as usize;
140            read_json_str(c, l)
141        }
142
143        0xC4 => {
144            let l = c.take()? as usize;
145            Ok(serde_json::Value::String(base64_encode(c.take_n(l)?)))
146        }
147        0xC5 => {
148            let l = c.read_u16_be()? as usize;
149            Ok(serde_json::Value::String(base64_encode(c.take_n(l)?)))
150        }
151        0xC6 => {
152            let l = c.read_u32_be()? as usize;
153            Ok(serde_json::Value::String(base64_encode(c.take_n(l)?)))
154        }
155
156        m @ 0x90..=0x9F => read_json_array(c, (m & 0x0F) as usize),
157        0xDC => {
158            let l = c.read_u16_be()? as usize;
159            read_json_array(c, l)
160        }
161        0xDD => {
162            let l = c.read_u32_be()? as usize;
163            read_json_array(c, l)
164        }
165
166        m @ 0x80..=0x8F => read_json_map(c, (m & 0x0F) as usize),
167        0xDE => {
168            let l = c.read_u16_be()? as usize;
169            read_json_map(c, l)
170        }
171        0xDF => {
172            let l = c.read_u32_be()? as usize;
173            read_json_map(c, l)
174        }
175
176        // ext types — skip
177        0xD4 => {
178            c.take_n(2)?;
179            Ok(serde_json::Value::Null)
180        }
181        0xD5 => {
182            c.take_n(3)?;
183            Ok(serde_json::Value::Null)
184        }
185        0xD6 => {
186            c.take_n(5)?;
187            Ok(serde_json::Value::Null)
188        }
189        0xD7 => {
190            c.take_n(9)?;
191            Ok(serde_json::Value::Null)
192        }
193        0xD8 => {
194            c.take_n(17)?;
195            Ok(serde_json::Value::Null)
196        }
197        0xC7 => {
198            let l = c.take()? as usize;
199            c.take_n(1 + l)?;
200            Ok(serde_json::Value::Null)
201        }
202        0xC8 => {
203            let l = c.read_u16_be()? as usize;
204            c.take_n(1 + l)?;
205            Ok(serde_json::Value::Null)
206        }
207        0xC9 => {
208            let l = c.read_u32_be()? as usize;
209            c.take_n(1 + l)?;
210            Ok(serde_json::Value::Null)
211        }
212
213        _ => Err(zerompk::Error::InvalidMarker(marker)),
214    }
215}
216
217fn read_json_str(c: &mut Cursor<'_>, len: usize) -> zerompk::Result<serde_json::Value> {
218    let bytes = c.take_n(len)?;
219    let s = String::from_utf8(bytes.to_vec()).map_err(|_| zerompk::Error::InvalidMarker(0))?;
220    Ok(serde_json::Value::String(s))
221}
222
223fn read_json_array(c: &mut Cursor<'_>, len: usize) -> zerompk::Result<serde_json::Value> {
224    c.depth += 1;
225    let mut arr = Vec::with_capacity(len.min(4096));
226    for _ in 0..len {
227        arr.push(read_json_value(c)?);
228    }
229    c.depth -= 1;
230    Ok(serde_json::Value::Array(arr))
231}
232
233fn read_json_map(c: &mut Cursor<'_>, len: usize) -> zerompk::Result<serde_json::Value> {
234    c.depth += 1;
235    let mut map = serde_json::Map::with_capacity(len.min(4096));
236    for _ in 0..len {
237        let key_marker = c.peek()?;
238        let key = if (0xA0..=0xBF).contains(&key_marker)
239            || key_marker == 0xD9
240            || key_marker == 0xDA
241            || key_marker == 0xDB
242        {
243            match read_json_value(c)? {
244                serde_json::Value::String(s) => s,
245                other => other.to_string(),
246            }
247        } else {
248            read_json_value(c)?.to_string()
249        };
250        let val = read_json_value(c)?;
251        map.insert(key, val);
252    }
253    c.depth -= 1;
254    Ok(serde_json::Value::Object(map))
255}
256
257// ── Native value reader ──
258
259fn read_native_value(c: &mut Cursor<'_>) -> zerompk::Result<crate::Value> {
260    if c.depth > 500 {
261        return Err(zerompk::Error::DepthLimitExceeded { max: 500 });
262    }
263
264    let marker = c.take()?;
265    match marker {
266        0xC0 => Ok(crate::Value::Null),
267        0xC2 => Ok(crate::Value::Bool(false)),
268        0xC3 => Ok(crate::Value::Bool(true)),
269
270        0x00..=0x7F => Ok(crate::Value::Integer(marker as i64)),
271        0xE0..=0xFF => Ok(crate::Value::Integer(marker as i8 as i64)),
272
273        0xCC => Ok(crate::Value::Integer(c.take()? as i64)),
274        0xCD => Ok(crate::Value::Integer(c.read_u16_be()? as i64)),
275        0xCE => Ok(crate::Value::Integer(c.read_u32_be()? as i64)),
276        0xCF => {
277            let b = c.take_n(8)?;
278            Ok(crate::Value::Integer(u64::from_be_bytes([
279                b[0], b[1], b[2], b[3], b[4], b[5], b[6], b[7],
280            ]) as i64))
281        }
282
283        0xD0 => Ok(crate::Value::Integer(c.take()? as i8 as i64)),
284        0xD1 => {
285            let b = c.take_n(2)?;
286            Ok(crate::Value::Integer(
287                i16::from_be_bytes([b[0], b[1]]) as i64
288            ))
289        }
290        0xD2 => {
291            let b = c.take_n(4)?;
292            Ok(crate::Value::Integer(
293                i32::from_be_bytes([b[0], b[1], b[2], b[3]]) as i64,
294            ))
295        }
296        0xD3 => {
297            let b = c.take_n(8)?;
298            Ok(crate::Value::Integer(i64::from_be_bytes([
299                b[0], b[1], b[2], b[3], b[4], b[5], b[6], b[7],
300            ])))
301        }
302
303        0xCA => {
304            let b = c.take_n(4)?;
305            Ok(crate::Value::Float(
306                f32::from_be_bytes([b[0], b[1], b[2], b[3]]) as f64,
307            ))
308        }
309        0xCB => {
310            let b = c.take_n(8)?;
311            Ok(crate::Value::Float(f64::from_be_bytes([
312                b[0], b[1], b[2], b[3], b[4], b[5], b[6], b[7],
313            ])))
314        }
315
316        m @ 0xA0..=0xBF => read_native_str(c, (m & 0x1F) as usize),
317        0xD9 => {
318            let l = c.take()? as usize;
319            read_native_str(c, l)
320        }
321        0xDA => {
322            let l = c.read_u16_be()? as usize;
323            read_native_str(c, l)
324        }
325        0xDB => {
326            let l = c.read_u32_be()? as usize;
327            read_native_str(c, l)
328        }
329
330        0xC4 => {
331            let l = c.take()? as usize;
332            Ok(crate::Value::Bytes(c.take_n(l)?.to_vec()))
333        }
334        0xC5 => {
335            let l = c.read_u16_be()? as usize;
336            Ok(crate::Value::Bytes(c.take_n(l)?.to_vec()))
337        }
338        0xC6 => {
339            let l = c.read_u32_be()? as usize;
340            Ok(crate::Value::Bytes(c.take_n(l)?.to_vec()))
341        }
342
343        m @ 0x90..=0x9F => read_native_array(c, (m & 0x0F) as usize),
344        0xDC => {
345            let l = c.read_u16_be()? as usize;
346            read_native_array(c, l)
347        }
348        0xDD => {
349            let l = c.read_u32_be()? as usize;
350            read_native_array(c, l)
351        }
352
353        m @ 0x80..=0x8F => read_native_map(c, (m & 0x0F) as usize),
354        0xDE => {
355            let l = c.read_u16_be()? as usize;
356            read_native_map(c, l)
357        }
358        0xDF => {
359            let l = c.read_u32_be()? as usize;
360            read_native_map(c, l)
361        }
362
363        // ext types — skip
364        0xD4 => {
365            c.take_n(2)?;
366            Ok(crate::Value::Null)
367        }
368        0xD5 => {
369            c.take_n(3)?;
370            Ok(crate::Value::Null)
371        }
372        0xD6 => {
373            c.take_n(5)?;
374            Ok(crate::Value::Null)
375        }
376        0xD7 => {
377            c.take_n(9)?;
378            Ok(crate::Value::Null)
379        }
380        0xD8 => {
381            c.take_n(17)?;
382            Ok(crate::Value::Null)
383        }
384        0xC7 => {
385            let l = c.take()? as usize;
386            c.take_n(1 + l)?;
387            Ok(crate::Value::Null)
388        }
389        0xC8 => {
390            let l = c.read_u16_be()? as usize;
391            c.take_n(1 + l)?;
392            Ok(crate::Value::Null)
393        }
394        0xC9 => {
395            let l = c.read_u32_be()? as usize;
396            c.take_n(1 + l)?;
397            Ok(crate::Value::Null)
398        }
399
400        _ => Err(zerompk::Error::InvalidMarker(marker)),
401    }
402}
403
404fn read_native_str(c: &mut Cursor<'_>, len: usize) -> zerompk::Result<crate::Value> {
405    let bytes = c.take_n(len)?;
406    let s = String::from_utf8(bytes.to_vec()).map_err(|_| zerompk::Error::InvalidMarker(0))?;
407    Ok(crate::Value::String(s))
408}
409
410fn read_native_array(c: &mut Cursor<'_>, len: usize) -> zerompk::Result<crate::Value> {
411    c.depth += 1;
412    let mut arr = Vec::with_capacity(len.min(4096));
413    for _ in 0..len {
414        arr.push(read_native_value(c)?);
415    }
416    c.depth -= 1;
417    Ok(crate::Value::Array(arr))
418}
419
420fn read_native_map(c: &mut Cursor<'_>, len: usize) -> zerompk::Result<crate::Value> {
421    c.depth += 1;
422    let mut map = std::collections::HashMap::with_capacity(len.min(4096));
423    for _ in 0..len {
424        let key_marker = c.peek()?;
425        let key = if (0xA0..=0xBF).contains(&key_marker)
426            || key_marker == 0xD9
427            || key_marker == 0xDA
428            || key_marker == 0xDB
429        {
430            match read_native_value(c)? {
431                crate::Value::String(s) => s,
432                other => format!("{other:?}"),
433            }
434        } else {
435            let v = read_native_value(c)?;
436            format!("{v:?}")
437        };
438        let val = read_native_value(c)?;
439        map.insert(key, val);
440    }
441    c.depth -= 1;
442    Ok(crate::Value::Object(map))
443}
444
445// ── Shared helpers ──
446
447pub(crate) fn base64_encode(data: &[u8]) -> String {
448    use std::fmt::Write;
449    const CHARS: &[u8; 64] = b"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
450    let mut out = String::with_capacity(data.len().div_ceil(3) * 4);
451    for chunk in data.chunks(3) {
452        let b0 = chunk[0] as u32;
453        let b1 = chunk.get(1).copied().unwrap_or(0) as u32;
454        let b2 = chunk.get(2).copied().unwrap_or(0) as u32;
455        let triple = (b0 << 16) | (b1 << 8) | b2;
456        let _ = write!(out, "{}", CHARS[((triple >> 18) & 0x3F) as usize] as char);
457        let _ = write!(out, "{}", CHARS[((triple >> 12) & 0x3F) as usize] as char);
458        if chunk.len() > 1 {
459            let _ = write!(out, "{}", CHARS[((triple >> 6) & 0x3F) as usize] as char);
460        }
461        if chunk.len() > 2 {
462            let _ = write!(out, "{}", CHARS[(triple & 0x3F) as usize] as char);
463        }
464    }
465    out
466}