Skip to main content

nextjson/formats/
ubjson.rs

1//! UBJSON codec (Universal Binary JSON, v5 / Draft 12).
2//!
3//! Self-describing binary JSON. Every value is `[type marker][payload]`; the
4//! "optimized" forms are the container parameters only:
5//!
6//! | Marker | Meaning |
7//! |---|---|
8//! | `Z` | null |
9//! | `T` / `F` | true / false |
10//! | `i` / `U` / `I` / `l` / `L` | int8 / uint8 / int16 / int32 / int64 (big-endian) |
11//! | `d` / `D` | float32 / float64 (big-endian) |
12//! | `H` | high-precision number (decimal string; used for >64-bit integers) |
13//! | `C` | char (deprecated, still read) |
14//! | `S` | string (integer length + UTF-8 bytes) |
15//! | `[` / `]` | array start / end |
16//! | `{` / `}` | object start / end |
17//! | `N` | no-op (skipped) |
18//! | `$` | typed container (all elements share one type) |
19//! | `#` | container count (counted containers have **no** end marker) |
20//!
21//! Wire rules matched to `serde_ubjson` for byte-level interop:
22//! - **Object keys** are `<integer length><utf-8 bytes>` with **no** `S`
23//!   marker (UBJSON quirk).
24//! - Integers cascade to the smallest type: `u64` emits `U` / `I` / `l` /
25//!   `L` and `H` (decimal string) beyond 63 bits, mirroring
26//!   `serde_ubjson`.
27//! - Byte strings are the typed array `[ $U #n <raw> ` (no end marker).
28//! - The encoder emits end-marker containers (`[ ... ]`, `{ ... }`); the
29//!   decoder also accepts counted (`[ #n ...`) and typed-counted
30//!   (`[ $t #n ...`) forms.
31//!
32//! The JSON-compatible profile rejects non-finite floats.
33
34use alloc::borrow::Cow;
35use alloc::string::ToString;
36use alloc::vec::Vec;
37
38use crate::de::{token_name, FormatDecoder, Mark, NsonDeserialize, Token};
39use crate::error::{Error, Result};
40use crate::formats::bin::{Cursor, MAX_CONTAINER_PREALLOC};
41use crate::formats::Format;
42use crate::number::Number;
43use crate::ser::{FormatEncoder, NsonSerialize};
44use crate::write::Write;
45
46/// UBJSON format marker.
47#[derive(Clone, Copy, Debug)]
48pub struct Ubjson;
49
50impl Format for Ubjson {
51    const NAME: &'static str = "ubjson";
52    const MIME: &'static str = "application/ubjson";
53    const EXTENSIONS: &'static [&'static str] = &["ubj", "ubjson"];
54    const BINARY: bool = true;
55
56    fn encode<T: NsonSerialize + ?Sized>(self, value: &T) -> Result<Vec<u8>> {
57        let mut encoder = UbjsonEncoder::new(Vec::new());
58        // Trusted path (derive emits a well-formed stream); container
59        // bookkeeping is structural and still rejects unbalanced output.
60        T::nextencode(value, &mut encoder)?;
61        Ok(encoder.finish_vec())
62    }
63
64    fn decode<'de, T: NsonDeserialize<'de>>(self, input: &'de [u8]) -> Result<T> {
65        let mut decoder = UbjsonDecoder::new(input);
66        let value = T::nextdecode(&mut decoder)?;
67        decoder.expect_end()?;
68        Ok(value)
69    }
70}
71
72// ---------------------------------------------------------------------------
73// Encoder
74// ---------------------------------------------------------------------------
75
76/// Streaming UBJSON encoder (end-marker containers).
77pub struct UbjsonEncoder<W: Write> {
78    writer: W,
79    buf: Vec<u8>,
80}
81
82impl<W: Write> UbjsonEncoder<W> {
83    /// Create a UBJSON encoder over `writer`.
84    pub fn new(writer: W) -> Self {
85        UbjsonEncoder {
86            writer,
87            buf: Vec::with_capacity(1024),
88        }
89    }
90
91    fn push(&mut self, byte: u8) {
92        self.buf.push(byte);
93    }
94
95    fn extend(&mut self, bytes: &[u8]) {
96        self.buf.extend_from_slice(bytes);
97    }
98
99    /// Encode a non-negative integer as a length / count (smallest unsigned
100    /// type; mirrors `serde_ubjson`'s length cascade).
101    fn write_length(&mut self, value: u64) {
102        if value <= u8::MAX as u64 {
103            self.push(b'U');
104            self.push(value as u8);
105        } else if value <= i16::MAX as u64 {
106            self.push(b'I');
107            self.extend(&(value as u16).to_be_bytes());
108        } else if value <= u32::MAX as u64 {
109            self.push(b'l');
110            self.extend(&(value as u32).to_be_bytes());
111        } else {
112            self.push(b'L');
113            self.extend(&value.to_be_bytes());
114        }
115    }
116
117    /// Encode a signed integer (smallest type; matches `serde_ubjson`).
118    fn write_signed(&mut self, value: i64) {
119        if (-128..=127).contains(&value) {
120            self.push(b'i');
121            self.push(value as u8);
122        } else if (0..=u8::MAX as i64).contains(&value) {
123            self.push(b'U');
124            self.push(value as u8);
125        } else if i16::try_from(value).is_ok() {
126            self.push(b'I');
127            self.extend(&(value as i16).to_be_bytes());
128        } else if i32::try_from(value).is_ok() {
129            self.push(b'l');
130            self.extend(&(value as i32).to_be_bytes());
131        } else {
132            self.push(b'L');
133            self.extend(&value.to_be_bytes());
134        }
135    }
136
137    /// Encode a non-negative integer (smallest type; matches `serde_ubjson`
138    /// for `u64`, which uses `H` beyond 63 bits).
139    fn write_unsigned(&mut self, value: u64) {
140        if value <= u8::MAX as u64 {
141            self.push(b'U');
142            self.push(value as u8);
143        } else if value <= i16::MAX as u64 {
144            self.push(b'I');
145            self.extend(&(value as u16).to_be_bytes());
146        } else if value <= i32::MAX as u64 {
147            self.push(b'l');
148            self.extend(&(value as u32).to_be_bytes());
149        } else if value <= i64::MAX as u64 {
150            self.push(b'L');
151            self.extend(&value.to_be_bytes());
152        } else {
153            // Beyond signed 63-bit range: high-precision decimal string.
154            self.write_high_precision(&value.to_string());
155        }
156    }
157
158    /// Emit a high-precision number: `H` + length + decimal digits.
159    fn write_high_precision(&mut self, text: &str) {
160        self.push(b'H');
161        self.write_length(text.len() as u64);
162        self.extend(text.as_bytes());
163    }
164
165    fn write_string(&mut self, value: &str) {
166        let bytes = value.as_bytes();
167        self.push(b'S');
168        self.write_length(bytes.len() as u64);
169        self.extend(bytes);
170    }
171
172    /// Flush the internal buffer and return the underlying writer.
173    pub fn finish(mut self) -> Result<W> {
174        self.writer.write_all(&self.buf)?;
175        self.writer.flush()?;
176        Ok(self.writer)
177    }
178
179    fn finish_vec(mut self) -> Vec<u8> {
180        core::mem::take(&mut self.buf)
181    }
182}
183
184impl<W: Write> FormatEncoder for UbjsonEncoder<W> {
185    type Error = crate::error::Error;
186
187    fn begin_array(&mut self) -> Result<(), Self::Error> {
188        self.push(b'[');
189        Ok(())
190    }
191
192    fn separator(&mut self) -> Result<(), Self::Error> {
193        Ok(())
194    }
195
196    fn end_array(&mut self) -> Result<(), Self::Error> {
197        self.push(b']');
198        Ok(())
199    }
200
201    fn begin_object(&mut self) -> Result<(), Self::Error> {
202        self.push(b'{');
203        Ok(())
204    }
205
206    fn key(&mut self, key: &str) -> Result<(), Self::Error> {
207        // UBJSON object keys are `<integer length><utf-8>` with no `S`
208        // marker.
209        self.write_length(key.len() as u64);
210        self.extend(key.as_bytes());
211        Ok(())
212    }
213
214    fn end_object(&mut self) -> Result<(), Self::Error> {
215        self.push(b'}');
216        Ok(())
217    }
218
219    fn write_null(&mut self) -> Result<(), Self::Error> {
220        self.push(b'Z');
221        Ok(())
222    }
223
224    fn write_bool(&mut self, value: bool) -> Result<(), Self::Error> {
225        self.push(if value { b'T' } else { b'F' });
226        Ok(())
227    }
228
229    fn write_str(&mut self, value: &str) -> Result<(), Self::Error> {
230        self.write_string(value);
231        Ok(())
232    }
233
234    fn write_char(&mut self, value: char) -> Result<(), Self::Error> {
235        let mut tmp = [0u8; 4];
236        self.write_string(value.encode_utf8(&mut tmp));
237        Ok(())
238    }
239
240    fn write_number(&mut self, value: &Number) -> Result<(), Self::Error> {
241        match *value {
242            Number::I64(v) => self.write_i64(v),
243            Number::U64(v) => self.write_u64(v),
244            Number::I128(v) => self.write_i128(v),
245            Number::U128(v) => self.write_u128(v),
246            Number::F64(v) => self.write_f64(v),
247        }
248    }
249
250    fn write_i64(&mut self, value: i64) -> Result<(), Self::Error> {
251        self.write_signed(value);
252        Ok(())
253    }
254
255    fn write_u64(&mut self, value: u64) -> Result<(), Self::Error> {
256        self.write_unsigned(value);
257        Ok(())
258    }
259
260    fn write_i128(&mut self, value: i128) -> Result<(), Self::Error> {
261        match i64::try_from(value) {
262            Ok(v) => {
263                self.write_signed(v);
264                Ok(())
265            }
266            Err(_) => {
267                // Out of 64-bit range: high-precision decimal string.
268                self.write_high_precision(&value.to_string());
269                Ok(())
270            }
271        }
272    }
273
274    fn write_u128(&mut self, value: u128) -> Result<(), Self::Error> {
275        match u64::try_from(value) {
276            Ok(v) => {
277                self.write_unsigned(v);
278                Ok(())
279            }
280            Err(_) => {
281                self.write_high_precision(&value.to_string());
282                Ok(())
283            }
284        }
285    }
286
287    fn write_f64(&mut self, value: f64) -> Result<(), Self::Error> {
288        if !value.is_finite() {
289            return Err(Error::custom("ubjson: non-finite float cannot be encoded"));
290        }
291        self.push(b'D');
292        self.extend(&value.to_be_bytes());
293        Ok(())
294    }
295
296    fn write_f32(&mut self, value: f32) -> Result<(), Self::Error> {
297        if !value.is_finite() {
298            return Err(Error::custom("ubjson: non-finite float cannot be encoded"));
299        }
300        self.push(b'd');
301        self.extend(&value.to_be_bytes());
302        Ok(())
303    }
304
305    fn write_bytes(&mut self, value: &[u8]) -> Result<(), Self::Error> {
306        // Typed counted uint8 array: `[ $U #n <raw>` — no end marker.
307        self.push(b'[');
308        self.push(b'$');
309        self.push(b'U');
310        self.push(b'#');
311        self.write_length(value.len() as u64);
312        self.extend(value);
313        Ok(())
314    }
315
316    fn is_human_readable(&self) -> bool {
317        false
318    }
319}
320
321// ---------------------------------------------------------------------------
322// Decoder
323// ---------------------------------------------------------------------------
324
325#[derive(Clone, Copy, PartialEq)]
326enum DFrameKind {
327    Array,
328    Object,
329}
330
331#[derive(Clone, Copy)]
332struct DFrame {
333    kind: DFrameKind,
334    /// Remaining elements/pairs in a counted container (`Some(0)` means the
335    /// count is exhausted and no end marker follows).
336    remaining: Option<u64>,
337    /// Element type in a typed container (`$type`).
338    typed: Option<u8>,
339}
340
341/// Streaming UBJSON decoder.
342pub struct UbjsonDecoder<'de> {
343    cur: Cursor<'de>,
344    lookahead: Option<u8>,
345    frames: Vec<DFrame>,
346    depth: u32,
347    max_depth: u32,
348}
349
350impl<'de> UbjsonDecoder<'de> {
351    /// Create a UBJSON decoder over `input`.
352    pub fn new(input: &'de [u8]) -> Self {
353        UbjsonDecoder {
354            cur: Cursor::new(input),
355            lookahead: None,
356            frames: Vec::new(),
357            depth: 0,
358            max_depth: 128,
359        }
360    }
361
362    /// Validate that the whole input was consumed.
363    pub fn end(&mut self) -> Result<()> {
364        self.expect_end()
365    }
366
367    fn expect_end(&mut self) -> Result<()> {
368        // Skip trailing no-op markers, tolerating clean EOF.
369        while !self.cur.at_end() {
370            if self.peek_byte()? != b'N' {
371                break;
372            }
373            self.next_byte()?;
374        }
375        if self.frames.is_empty() && self.lookahead.is_none() && self.cur.at_end() {
376            Ok(())
377        } else {
378            Err(Error::custom("ubjson: trailing bytes after value"))
379        }
380    }
381
382    #[inline]
383    fn peek_byte(&mut self) -> Result<u8> {
384        if let Some(byte) = self.lookahead {
385            return Ok(byte);
386        }
387        let byte = self.cur.peek()?;
388        self.lookahead = Some(byte);
389        Ok(byte)
390    }
391
392    #[inline]
393    fn next_byte(&mut self) -> Result<u8> {
394        if let Some(byte) = self.lookahead.take() {
395            // The lookahead byte sits at the cursor position; consuming it
396            // must advance the cursor past it.
397            self.cur.seek(self.cur.pos() + 1);
398            return Ok(byte);
399        }
400        self.cur.byte()
401    }
402
403    fn enter_container(&mut self) -> Result<()> {
404        if self.depth >= self.max_depth {
405            return Err(Error::custom("ubjson: recursion limit exceeded"));
406        }
407        self.depth += 1;
408        Ok(())
409    }
410
411    /// Read the type marker for the next value.
412    ///
413    /// Inside a typed container the element type is pinned and no marker
414    /// byte is consumed; elsewhere the marker byte is read (skipping no-ops).
415    fn value_marker(&mut self) -> Result<u8> {
416        if let Some(frame) = self.frames.last() {
417            if let Some(typed) = frame.typed {
418                if frame.kind == DFrameKind::Array {
419                    // The cursor already points at the first raw payload
420                    // byte; drop any pending peek of that same byte.
421                    self.lookahead = None;
422                    return Ok(typed);
423                }
424            }
425        }
426        loop {
427            let marker = self.next_byte()?;
428            if marker != b'N' {
429                return Ok(marker);
430            }
431        }
432    }
433
434    /// Read an integer length / count (`U`/`I`/`l`/`L`, or `i` for
435    /// tolerance). Negative values are invalid as lengths.
436    fn read_length(&mut self) -> Result<u64> {
437        let marker = self.next_byte()?;
438        match marker {
439            b'U' => Ok(self.cur.byte()? as u64),
440            b'i' => {
441                let value = self.cur.byte()? as i8;
442                if value < 0 {
443                    Err(Error::custom("ubjson: negative length"))
444                } else {
445                    Ok(value as u64)
446                }
447            }
448            b'I' => Ok(self.cur.be_u16()? as u64),
449            b'l' => {
450                let value = self.cur.be_u32()? as i32;
451                if value < 0 {
452                    Err(Error::custom("ubjson: negative length"))
453                } else {
454                    Ok(value as u64)
455                }
456            }
457            b'L' => Ok(self.cur.be_u64()?),
458            other => Err(Error::custom(alloc::format!(
459                "ubjson: expected integer length, got 0x{other:02x}"
460            ))),
461        }
462    }
463
464    fn read_number_marker(&mut self) -> Result<Number> {
465        let marker = self.value_marker()?;
466        match marker {
467            b'i' => Ok(Number::from(self.cur.byte()? as i8)),
468            b'U' => Ok(Number::U64(self.cur.byte()? as u64)),
469            b'I' => Ok(Number::from(self.cur.be_u16()? as i16)),
470            b'l' => Ok(Number::from(self.cur.be_u32()? as i32)),
471            b'L' => Ok(Number::from(self.cur.be_u64()? as i64)),
472            b'd' => {
473                let raw = self.cur.take(4)?;
474                let mut a = [0u8; 4];
475                a.copy_from_slice(raw);
476                Ok(Number::F64(f32::from_be_bytes(a) as f64))
477            }
478            b'D' => {
479                let raw = self.cur.take(8)?;
480                let mut a = [0u8; 8];
481                a.copy_from_slice(raw);
482                let value = f64::from_be_bytes(a);
483                if !value.is_finite() {
484                    return Err(Error::custom("ubjson: non-finite float"));
485                }
486                Ok(Number::F64(value))
487            }
488            b'H' => {
489                let len = usize::try_from(self.read_length()?)
490                    .map_err(|_| Error::custom("ubjson: high-precision length too large"))?;
491                let text = self.cur.take(len)?;
492                // High-precision payload is a decimal string; keep integer
493                // values exact (floaty text takes the float path).
494                let is_float = text.iter().any(|b| matches!(b, b'.' | b'e' | b'E'));
495                let parsed = Number::parse(text, is_float)
496                    .map_err(|_| Error::custom("ubjson: invalid high-precision number"))?;
497                Ok(parsed)
498            }
499            other => Err(Error::custom(alloc::format!(
500                "ubjson: expected number, got 0x{other:02x}"
501            ))),
502        }
503    }
504
505    /// Read a string value: `S` (marker + length + bytes) or `C` (char).
506    fn read_string_marker(&mut self) -> Result<Cow<'de, str>> {
507        let marker = self.value_marker()?;
508        match marker {
509            b'S' => {
510                let len = usize::try_from(self.read_length()?)
511                    .map_err(|_| Error::custom("ubjson: string length too large"))?;
512                let bytes = self.cur.take(len)?;
513                let s = core::str::from_utf8(bytes)
514                    .map_err(|_| Error::custom("ubjson: invalid utf-8"))?;
515                Ok(Cow::Borrowed(s))
516            }
517            b'C' => {
518                let byte = self.cur.byte()?;
519                let c = core::char::from_u32(byte as u32)
520                    .ok_or_else(|| Error::custom("ubjson: invalid char byte"))?;
521                let mut tmp = [0u8; 4];
522                Ok(Cow::Owned(c.encode_utf8(&mut tmp).to_string()))
523            }
524            other => Err(Error::custom(alloc::format!(
525                "ubjson: expected string, got 0x{other:02x}"
526            ))),
527        }
528    }
529
530    /// Read an object key: `<integer length><utf-8 bytes>` (no `S` marker).
531    fn read_key(&mut self) -> Result<Cow<'de, str>> {
532        let len = usize::try_from(self.read_length()?)
533            .map_err(|_| Error::custom("ubjson: key length too large"))?;
534        let bytes = self.cur.take(len)?;
535        let s =
536            core::str::from_utf8(bytes).map_err(|_| Error::custom("ubjson: invalid utf-8 key"))?;
537        Ok(Cow::Borrowed(s))
538    }
539
540    /// Parse the container header (which may carry `$type` and/or `#count`).
541    fn parse_container_header(&mut self, kind: DFrameKind) -> Result<DFrame> {
542        let mut typed = None;
543        let mut remaining = None;
544        loop {
545            match self.peek_byte()? {
546                b'$' => {
547                    self.next_byte()?;
548                    typed = Some(self.next_byte()?);
549                }
550                b'#' => {
551                    self.next_byte()?;
552                    remaining = Some(self.read_length()?);
553                }
554                _ => break,
555            }
556        }
557        Ok(DFrame {
558            kind,
559            remaining,
560            typed,
561        })
562    }
563
564    /// Consume a container terminator: `]`/`}` for end-marker containers,
565    /// nothing for counted containers.
566    fn take_end(&mut self, expected: u8, counted: bool) -> Result<()> {
567        if counted {
568            return Ok(());
569        }
570        let byte = self.next_byte()?;
571        if byte != expected {
572            return Err(Error::custom(alloc::format!(
573                "ubjson: expected 0x{expected:02x}, got 0x{byte:02x}"
574            )));
575        }
576        Ok(())
577    }
578}
579
580impl<'de> FormatDecoder<'de> for UbjsonDecoder<'de> {
581    type Error = crate::error::Error;
582
583    fn begin_object(&mut self) -> Result<(), Self::Error> {
584        self.enter_container()?;
585        match self.next_byte()? {
586            b'{' => {
587                let frame = self.parse_container_header(DFrameKind::Object)?;
588                self.frames.push(frame);
589                Ok(())
590            }
591            other => Err(Error::invalid_type("a map", token_for(other))),
592        }
593    }
594
595    fn end_object(&mut self) -> Result<(), Self::Error> {
596        let frame = self
597            .frames
598            .pop()
599            .ok_or_else(|| Error::custom("ubjson: object end without start"))?;
600        if frame.kind != DFrameKind::Object {
601            return Err(Error::custom("ubjson: mismatched object end"));
602        }
603        self.take_end(b'}', frame.remaining.is_some())?;
604        self.depth = self.depth.saturating_sub(1);
605        Ok(())
606    }
607
608    fn object_key(&mut self) -> Result<Option<Cow<'de, str>>, Self::Error> {
609        {
610            let frame = self
611                .frames
612                .last()
613                .ok_or_else(|| Error::custom("ubjson: object key outside object"))?;
614            if let Some(remaining) = frame.remaining {
615                if remaining == 0 {
616                    return Ok(None);
617                }
618            }
619        }
620        match self.peek_byte()? {
621            b'}' => Ok(None),
622            _ => {
623                let key = self.read_key()?;
624                if let Some(frame) = self.frames.last_mut() {
625                    if let Some(remaining) = &mut frame.remaining {
626                        *remaining -= 1;
627                    }
628                }
629                Ok(Some(key))
630            }
631        }
632    }
633
634    fn object_entry_sep(&mut self) -> Result<bool, Self::Error> {
635        if let Some(frame) = self.frames.last() {
636            if let Some(remaining) = frame.remaining {
637                return Ok(remaining > 0);
638            }
639        }
640        Ok(self.peek_byte()? != b'}')
641    }
642
643    fn begin_array(&mut self) -> Result<(), Self::Error> {
644        self.enter_container()?;
645        match self.next_byte()? {
646            b'[' => {
647                let frame = self.parse_container_header(DFrameKind::Array)?;
648                self.frames.push(frame);
649                Ok(())
650            }
651            other => Err(Error::invalid_type("an array", token_for(other))),
652        }
653    }
654
655    fn end_array(&mut self) -> Result<(), Self::Error> {
656        let frame = self
657            .frames
658            .pop()
659            .ok_or_else(|| Error::custom("ubjson: array end without start"))?;
660        if frame.kind != DFrameKind::Array {
661            return Err(Error::custom("ubjson: mismatched array end"));
662        }
663        self.take_end(b']', frame.remaining.is_some())?;
664        self.depth = self.depth.saturating_sub(1);
665        Ok(())
666    }
667
668    fn array_has_more(&mut self) -> Result<bool, Self::Error> {
669        let frame = self
670            .frames
671            .last()
672            .ok_or_else(|| Error::custom("ubjson: array access outside array"))?;
673        if let Some(remaining) = frame.remaining {
674            Ok(remaining > 0)
675        } else {
676            Ok(self.peek_byte()? != b']')
677        }
678    }
679
680    fn array_entry_sep(&mut self) -> Result<bool, Self::Error> {
681        if let Some(frame) = self.frames.last_mut() {
682            if let Some(remaining) = &mut frame.remaining {
683                if *remaining > 0 {
684                    *remaining -= 1;
685                }
686                return Ok(*remaining > 0);
687            }
688        }
689        Ok(self.peek_byte()? != b']')
690    }
691
692    fn array_len_hint(&self) -> Option<usize> {
693        self.frames.last().and_then(|frame| {
694            frame.remaining.map(|remaining| {
695                usize::try_from(remaining)
696                    .unwrap_or(usize::MAX)
697                    .min(self.cur.remaining_len())
698                    .min(MAX_CONTAINER_PREALLOC)
699            })
700        })
701    }
702
703    fn object_len_hint(&self) -> Option<usize> {
704        self.frames.last().and_then(|frame| {
705            frame.remaining.map(|remaining| {
706                usize::try_from(remaining)
707                    .unwrap_or(usize::MAX)
708                    .min(self.cur.remaining_len())
709                    .min(MAX_CONTAINER_PREALLOC)
710            })
711        })
712    }
713
714    fn unit(&mut self) -> Result<(), Self::Error> {
715        match self.value_marker()? {
716            b'Z' => Ok(()),
717            other => Err(Error::invalid_type("null", token_for(other))),
718        }
719    }
720
721    fn bool(&mut self) -> Result<bool, Self::Error> {
722        match self.value_marker()? {
723            b'T' => Ok(true),
724            b'F' => Ok(false),
725            other => Err(Error::invalid_type("bool", token_for(other))),
726        }
727    }
728
729    fn number(&mut self) -> Result<Number, Self::Error> {
730        self.read_number_marker()
731    }
732
733    fn string(&mut self) -> Result<Cow<'de, str>, Self::Error> {
734        self.read_string_marker()
735    }
736
737    fn char(&mut self) -> Result<char, Self::Error> {
738        let s = self.read_string_marker()?;
739        let mut chars = s.chars();
740        let c = chars
741            .next()
742            .ok_or_else(|| Error::custom("ubjson: empty char"))?;
743        if chars.next().is_some() {
744            return Err(Error::custom("ubjson: char is not a single scalar"));
745        }
746        Ok(c)
747    }
748
749    fn skip_value(&mut self) -> Result<(), Self::Error> {
750        // Byte-directed recursion without constructing intermediate values.
751        let marker = self.value_marker()?;
752        match marker {
753            b'Z' | b'T' | b'F' | b'N' => Ok(()),
754            b'i' | b'U' => {
755                self.cur.take(1)?;
756                Ok(())
757            }
758            b'I' => {
759                self.cur.take(2)?;
760                Ok(())
761            }
762            b'l' => {
763                self.cur.take(4)?;
764                Ok(())
765            }
766            b'L' => {
767                self.cur.take(8)?;
768                Ok(())
769            }
770            b'd' => {
771                self.cur.take(4)?;
772                Ok(())
773            }
774            b'D' => {
775                self.cur.take(8)?;
776                Ok(())
777            }
778            b'S' | b'H' => {
779                let len = usize::try_from(self.read_length()?)
780                    .map_err(|_| Error::custom("ubjson: length too large"))?;
781                self.cur.take(len)?;
782                Ok(())
783            }
784            b'C' => {
785                self.cur.take(1)?;
786                Ok(())
787            }
788            b'[' => {
789                self.enter_container()?;
790                let frame = self.parse_container_header(DFrameKind::Array)?;
791                self.frames.push(frame);
792                while self.array_has_more()? {
793                    self.skip_value()?;
794                    self.array_entry_sep()?;
795                }
796                self.end_array()?;
797                Ok(())
798            }
799            b'{' => {
800                self.enter_container()?;
801                let frame = self.parse_container_header(DFrameKind::Object)?;
802                self.frames.push(frame);
803                while self.object_key()?.is_some() {
804                    self.skip_value()?;
805                }
806                self.end_object()?;
807                Ok(())
808            }
809            other => Err(Error::custom(alloc::format!(
810                "ubjson: cannot skip value 0x{other:02x}"
811            ))),
812        }
813    }
814
815    fn peek_token(&mut self) -> Result<Token<'de>, Self::Error> {
816        let byte = self.peek_byte()?;
817        match byte {
818            b'Z' => Ok(Token::Null),
819            b'T' => Ok(Token::Bool(true)),
820            b'F' => Ok(Token::Bool(false)),
821            b'[' => Ok(Token::BeginArray),
822            b'{' => Ok(Token::BeginObject),
823            _ => {
824                if let Some(frame) = self.frames.last() {
825                    if let Some(typed) = frame.typed {
826                        return Ok(marker_token(typed));
827                    }
828                }
829                Ok(marker_token(byte))
830            }
831        }
832    }
833
834    fn next_token(&mut self) -> Result<Token<'de>, Self::Error> {
835        let byte = self.value_marker()?;
836        match byte {
837            b'Z' => Ok(Token::Null),
838            b'T' => Ok(Token::Bool(true)),
839            b'F' => Ok(Token::Bool(false)),
840            b'[' => {
841                self.enter_container()?;
842                let frame = self.parse_container_header(DFrameKind::Array)?;
843                self.frames.push(frame);
844                Ok(Token::BeginArray)
845            }
846            b'{' => {
847                self.enter_container()?;
848                let frame = self.parse_container_header(DFrameKind::Object)?;
849                self.frames.push(frame);
850                Ok(Token::BeginObject)
851            }
852            _ => Ok(marker_token(byte)),
853        }
854    }
855
856    fn save(&self) -> Mark {
857        Mark {
858            pos: self.cur.pos(),
859            depth: self.depth,
860            frame_len: self.frames.len(),
861        }
862    }
863
864    fn restore(&mut self, mark: Mark) {
865        self.cur.seek(mark.pos);
866        self.lookahead = None;
867        self.frames.truncate(mark.frame_len);
868        self.depth = mark.depth;
869    }
870
871    fn is_human_readable(&self) -> bool {
872        false
873    }
874}
875
876/// Map a marker byte to its [`Token`] shape (for error messages and peeks).
877fn marker_token(byte: u8) -> Token<'static> {
878    match byte {
879        b'Z' => Token::Null,
880        b'T' => Token::Bool(true),
881        b'F' => Token::Bool(false),
882        b'[' => Token::BeginArray,
883        b'{' => Token::BeginObject,
884        b']' => Token::EndArray,
885        b'}' => Token::EndObject,
886        b'S' | b'C' => Token::Str(Cow::Borrowed("")),
887        b'i' | b'U' | b'I' | b'l' | b'L' | b'd' | b'D' | b'H' => Token::Number(Number::U64(0)),
888        _ => Token::Str(Cow::Borrowed("")),
889    }
890}
891
892fn token_for(byte: u8) -> &'static str {
893    token_name(&marker_token(byte))
894}