Skip to main content

nextjson/formats/
cbor.rs

1//! Native CBOR codec (RFC 8949, JSON-compatible profile).
2//!
3//! Replaces the historical event-relay implementation (which serialized to
4//! JSON text and re-parsed it to produce CBOR, ~6-10x slower). This codec
5//! writes CBOR directly through the unified [`FormatEncoder`] contract and
6//! reads it directly through [`FormatDecoder`], eliminating the intermediate
7//! JSON round-trip while keeping the exact same wire semantics:
8//!
9//! - **Definite-length** arrays/maps with a count prefix (the compact,
10//!   standard form; the historical relay wrote indefinite-length, which is
11//!   still read for interoperability).
12//! - Integers through `u64` use major types 0/1; larger values use the
13//!   standard bignum tags 2 (unsigned) and 3 (negative).
14//! - Floats are written as 64-bit (double); half/float/double are read.
15//! - Non-finite floats are rejected (the JSON-compatible profile cannot
16//!   represent them), as are byte strings, non-text map keys, and semantic
17//!   tags other than 2/3 — matching the documented relay behavior.
18//!
19//! Both the cross-format relay (`crate::cross_format`) and this codec stay
20//! wire-compatible with each other and with external CBOR writers/readers;
21//! the foreign-wire fixtures in the test suite cover definite-length maps,
22//! half-floats, indefinite text chunks, and bignums.
23
24use alloc::borrow::Cow;
25use alloc::string::String;
26use alloc::vec::Vec;
27
28use crate::cross_format::half_to_f32;
29use crate::de::{token_name, FormatDecoder, Mark, NsonDeserialize, Token};
30use crate::error::{Error, Result};
31use crate::formats::bin::{patch_prefix, Cursor, MAX_CONTAINER_PREALLOC};
32use crate::formats::Format;
33use crate::number::Number;
34use crate::ser::{FormatEncoder, NsonSerialize};
35use crate::write::Write;
36
37/// CBOR format marker.
38#[derive(Clone, Copy, Debug)]
39pub struct Cbor;
40
41impl Format for Cbor {
42    const NAME: &'static str = "cbor";
43    const MIME: &'static str = "application/cbor";
44    const EXTENSIONS: &'static [&'static str] = &["cbor"];
45    const BINARY: bool = true;
46
47    fn encode<T: NsonSerialize + ?Sized>(self, value: &T) -> Result<Vec<u8>> {
48        let mut encoder = CborEncoder::new(Vec::new());
49        // Trust model matches the top-level JSON `FastEncoder`: derive code
50        // emits a well-formed event stream, and the encoder still counts
51        // container entries (required for definite-length headers), so
52        // unbalanced containers are rejected rather than producing garbage.
53        T::nextencode(value, &mut encoder)?;
54        Ok(encoder.finish_vec())
55    }
56
57    fn decode<'de, T: NsonDeserialize<'de>>(self, input: &'de [u8]) -> Result<T> {
58        let mut decoder = CborDecoder::new(input);
59        let value = T::nextdecode(&mut decoder)?;
60        decoder.expect_end()?;
61        Ok(value)
62    }
63}
64
65// ---------------------------------------------------------------------------
66// Encoder
67// ---------------------------------------------------------------------------
68
69#[derive(Clone, Copy, PartialEq)]
70enum FrameKind {
71    Array,
72    Map,
73}
74
75struct Frame {
76    start: usize,
77    kind: FrameKind,
78    count: u64,
79}
80
81/// Streaming CBOR encoder (definite-length containers).
82pub struct CborEncoder<W: Write> {
83    writer: W,
84    buf: Vec<u8>,
85    frames: Vec<Frame>,
86}
87
88impl<W: Write> CborEncoder<W> {
89    /// Create a CBOR encoder over `writer`.
90    pub fn new(writer: W) -> Self {
91        CborEncoder {
92            writer,
93            buf: Vec::with_capacity(1024),
94            frames: Vec::new(),
95        }
96    }
97
98    fn push(&mut self, byte: u8) {
99        self.buf.push(byte);
100    }
101
102    fn extend(&mut self, bytes: &[u8]) {
103        self.buf.extend_from_slice(bytes);
104    }
105
106    /// Emit a major-type header with the shortest argument encoding.
107    fn type_and_argument(&mut self, major: u8, argument: u64) {
108        let prefix = major << 5;
109        if argument < 24 {
110            self.push(prefix | argument as u8);
111        } else if argument <= u8::MAX as u64 {
112            self.extend(&[prefix | 24, argument as u8]);
113        } else if argument <= u16::MAX as u64 {
114            self.extend(&[prefix | 25]);
115            self.extend(&(argument as u16).to_be_bytes());
116        } else if argument <= u32::MAX as u64 {
117            self.extend(&[prefix | 26]);
118            self.extend(&(argument as u32).to_be_bytes());
119        } else {
120            self.extend(&[prefix | 27]);
121            self.extend(&argument.to_be_bytes());
122        }
123    }
124
125    fn unsigned(&mut self, value: u128) {
126        if let Ok(value) = u64::try_from(value) {
127            self.type_and_argument(0, value);
128        } else {
129            self.bignum(2, value);
130        }
131    }
132
133    fn signed(&mut self, value: i128) {
134        if value >= 0 {
135            return self.unsigned(value as u128);
136        }
137        let argument = (-1 - value) as u128;
138        if let Ok(argument) = u64::try_from(argument) {
139            self.type_and_argument(1, argument);
140        } else {
141            self.bignum(3, argument);
142        }
143    }
144
145    /// Bignum tags 2/3: `tag(value)` followed by a byte string of the
146    /// minimal big-endian magnitude.
147    fn bignum(&mut self, tag: u64, value: u128) {
148        self.type_and_argument(6, tag);
149        let bytes = value.to_be_bytes();
150        let first = bytes
151            .iter()
152            .position(|byte| *byte != 0)
153            .unwrap_or(bytes.len() - 1);
154        let magnitude = &bytes[first..];
155        self.type_and_argument(2, magnitude.len() as u64);
156        self.extend(magnitude);
157    }
158
159    fn write_string(&mut self, value: &str) {
160        let len = u64::try_from(value.len()).expect("string length fits u64");
161        self.type_and_argument(3, len);
162        self.extend(value.as_bytes());
163    }
164
165    fn patch_container(&mut self, frame: Frame) {
166        let count = frame.count;
167        // Placeholder was a single byte (`0x80` for array / `0xA0` for map).
168        let mut header = [0u8; 9];
169        let header_len = match frame.kind {
170            FrameKind::Array => {
171                if count < 24 {
172                    self.buf[frame.start] = 0x80 | count as u8;
173                    return;
174                } else if count <= u8::MAX as u64 {
175                    header[0] = 0x98;
176                    header[1] = count as u8;
177                    2
178                } else if count <= u16::MAX as u64 {
179                    header[0] = 0x99;
180                    header[1..3].copy_from_slice(&(count as u16).to_be_bytes());
181                    3
182                } else if count <= u32::MAX as u64 {
183                    header[0] = 0x9A;
184                    header[1..5].copy_from_slice(&(count as u32).to_be_bytes());
185                    5
186                } else {
187                    header[0] = 0x9B;
188                    header[1..9].copy_from_slice(&count.to_be_bytes());
189                    9
190                }
191            }
192            FrameKind::Map => {
193                if count < 24 {
194                    self.buf[frame.start] = 0xA0 | count as u8;
195                    return;
196                } else if count <= u8::MAX as u64 {
197                    header[0] = 0xB8;
198                    header[1] = count as u8;
199                    2
200                } else if count <= u16::MAX as u64 {
201                    header[0] = 0xB9;
202                    header[1..3].copy_from_slice(&(count as u16).to_be_bytes());
203                    3
204                } else if count <= u32::MAX as u64 {
205                    header[0] = 0xBA;
206                    header[1..5].copy_from_slice(&(count as u32).to_be_bytes());
207                    5
208                } else {
209                    header[0] = 0xBB;
210                    header[1..9].copy_from_slice(&count.to_be_bytes());
211                    9
212                }
213            }
214        };
215        patch_prefix(&mut self.buf, frame.start, &header[..header_len]);
216    }
217
218    /// Flush the internal buffer and return the underlying writer.
219    pub fn finish(mut self) -> Result<W> {
220        self.writer.write_all(&self.buf)?;
221        self.buf.clear();
222        self.writer.flush()?;
223        Ok(self.writer)
224    }
225
226    fn finish_vec(mut self) -> Vec<u8> {
227        core::mem::take(&mut self.buf)
228    }
229}
230
231impl<W: Write> FormatEncoder for CborEncoder<W> {
232    type Error = crate::error::Error;
233
234    fn begin_array(&mut self) -> Result<(), Self::Error> {
235        self.frames.push(Frame {
236            start: self.buf.len(),
237            kind: FrameKind::Array,
238            count: 0,
239        });
240        self.push(0x80); // placeholder array(0)
241        Ok(())
242    }
243
244    fn separator(&mut self) -> Result<(), Self::Error> {
245        let frame = self
246            .frames
247            .last_mut()
248            .ok_or_else(|| Error::custom("cbor: array separator outside a container"))?;
249        frame.count = frame
250            .count
251            .checked_add(1)
252            .ok_or_else(|| Error::custom("cbor: array length overflow"))?;
253        Ok(())
254    }
255
256    fn end_array(&mut self) -> Result<(), Self::Error> {
257        let frame = self
258            .frames
259            .pop()
260            .ok_or_else(|| Error::custom("cbor: array end without start"))?;
261        self.patch_container(frame);
262        Ok(())
263    }
264
265    fn begin_object(&mut self) -> Result<(), Self::Error> {
266        self.frames.push(Frame {
267            start: self.buf.len(),
268            kind: FrameKind::Map,
269            count: 0,
270        });
271        self.push(0xA0); // placeholder map(0)
272        Ok(())
273    }
274
275    fn key(&mut self, key: &str) -> Result<(), Self::Error> {
276        let frame = self
277            .frames
278            .last_mut()
279            .ok_or_else(|| Error::custom("cbor: object key outside a container"))?;
280        frame.count = frame
281            .count
282            .checked_add(1)
283            .ok_or_else(|| Error::custom("cbor: map length overflow"))?;
284        self.write_string(key);
285        Ok(())
286    }
287
288    fn end_object(&mut self) -> Result<(), Self::Error> {
289        let frame = self
290            .frames
291            .pop()
292            .ok_or_else(|| Error::custom("cbor: object end without start"))?;
293        self.patch_container(frame);
294        Ok(())
295    }
296
297    fn write_null(&mut self) -> Result<(), Self::Error> {
298        self.push(0xF6);
299        Ok(())
300    }
301
302    fn write_bool(&mut self, value: bool) -> Result<(), Self::Error> {
303        self.push(if value { 0xF5 } else { 0xF4 });
304        Ok(())
305    }
306
307    fn write_str(&mut self, value: &str) -> Result<(), Self::Error> {
308        self.write_string(value);
309        Ok(())
310    }
311
312    fn write_char(&mut self, value: char) -> Result<(), Self::Error> {
313        let mut buf = [0u8; 4];
314        self.write_string(value.encode_utf8(&mut buf));
315        Ok(())
316    }
317
318    fn write_number(&mut self, value: &Number) -> Result<(), Self::Error> {
319        match *value {
320            Number::I64(v) => self.write_i64(v),
321            Number::U64(v) => self.write_u64(v),
322            Number::I128(v) => self.write_i128(v),
323            Number::U128(v) => self.write_u128(v),
324            Number::F64(v) => self.write_f64(v),
325        }
326    }
327
328    fn write_i64(&mut self, value: i64) -> Result<(), Self::Error> {
329        self.signed(value as i128);
330        Ok(())
331    }
332
333    fn write_u64(&mut self, value: u64) -> Result<(), Self::Error> {
334        self.unsigned(value as u128);
335        Ok(())
336    }
337
338    fn write_i128(&mut self, value: i128) -> Result<(), Self::Error> {
339        self.signed(value);
340        Ok(())
341    }
342
343    fn write_u128(&mut self, value: u128) -> Result<(), Self::Error> {
344        self.unsigned(value);
345        Ok(())
346    }
347
348    fn write_f64(&mut self, value: f64) -> Result<(), Self::Error> {
349        if !value.is_finite() {
350            return Err(Error::custom("CBOR profile rejects non-finite floats"));
351        }
352        self.push(0xFB);
353        self.extend(&value.to_bits().to_be_bytes());
354        Ok(())
355    }
356
357    fn write_f32(&mut self, value: f32) -> Result<(), Self::Error> {
358        if !value.is_finite() {
359            return Err(Error::custom("CBOR profile rejects non-finite floats"));
360        }
361        self.push(0xFA);
362        self.extend(&value.to_bits().to_be_bytes());
363        Ok(())
364    }
365
366    fn is_human_readable(&self) -> bool {
367        false
368    }
369}
370
371// ---------------------------------------------------------------------------
372// Decoder
373// ---------------------------------------------------------------------------
374
375/// Decoder-side container frame. `remaining: Some(n)` is a definite-length
376/// container with `n` entries left; `None` is an indefinite container
377/// terminated by a break marker.
378#[derive(Clone, Copy)]
379struct DFrame {
380    kind: FrameKind,
381    remaining: Option<u64>,
382}
383
384/// Streaming CBOR decoder (definite + indefinite containers).
385pub struct CborDecoder<'de> {
386    cur: Cursor<'de>,
387    lookahead: Option<Token<'de>>,
388    pending: Option<DFrame>,
389    frames: Vec<DFrame>,
390    depth: u32,
391    max_depth: u32,
392}
393
394impl<'de> CborDecoder<'de> {
395    /// Create a decoder over `input`.
396    pub fn new(input: &'de [u8]) -> Self {
397        CborDecoder {
398            cur: Cursor::new(input),
399            lookahead: None,
400            pending: None,
401            frames: Vec::new(),
402            depth: 0,
403            max_depth: 128,
404        }
405    }
406
407    /// Validate that the whole input was consumed.
408    pub fn end(&mut self) -> Result<()> {
409        self.expect_end()
410    }
411
412    fn expect_end(&mut self) -> Result<()> {
413        if self.lookahead.is_none() && self.frames.is_empty() && self.cur.at_end() {
414            Ok(())
415        } else {
416            Err(Error::custom("cbor: trailing bytes after value"))
417        }
418    }
419
420    fn header(&mut self) -> Result<u8> {
421        self.cur.byte()
422    }
423
424    fn read_u8(&mut self) -> Result<u8> {
425        self.cur.byte()
426    }
427
428    fn read_be_u16(&mut self) -> Result<u16> {
429        self.cur.be_u16()
430    }
431
432    fn read_be_u32(&mut self) -> Result<u32> {
433        self.cur.be_u32()
434    }
435
436    fn read_be_u64(&mut self) -> Result<u64> {
437        self.cur.be_u64()
438    }
439
440    fn enter_container(&mut self) -> Result<()> {
441        if self.depth >= self.max_depth {
442            return Err(Error::custom("cbor: recursion limit exceeded"));
443        }
444        self.depth += 1;
445        Ok(())
446    }
447
448    /// Decode an argument (additional info 0..=27) into its value.
449    fn argument(&mut self, additional: u8) -> Result<u64> {
450        match additional {
451            0..=23 => Ok(additional as u64),
452            24 => Ok(self.read_u8()? as u64),
453            25 => Ok(self.read_be_u16()? as u64),
454            26 => Ok(self.read_be_u32()? as u64),
455            27 => self.read_be_u64(),
456            28..=30 => Err(Error::custom("cbor: reserved additional information")),
457            31 => Err(Error::custom("cbor: unexpected break marker")),
458            // `additional` is always `header & 0x1F`; the arm keeps the match
459            // exhaustive over `u8` and treats out-of-range input as invalid.
460            _ => Err(Error::custom("cbor: invalid additional information")),
461        }
462    }
463
464    /// Decode a container length; `31` (indefinite) yields `None`.
465    fn container_argument(&mut self, additional: u8) -> Result<Option<u64>> {
466        match additional {
467            0..=23 => Ok(Some(additional as u64)),
468            24 => Ok(Some(self.read_u8()? as u64)),
469            25 => Ok(Some(self.read_be_u16()? as u64)),
470            26 => Ok(Some(self.read_be_u32()? as u64)),
471            27 => Ok(Some(self.read_be_u64()?)),
472            28..=30 => Err(Error::custom("cbor: reserved additional information")),
473            31 => Ok(None),
474            _ => Err(Error::custom("cbor: invalid additional information")),
475        }
476    }
477
478    fn read_text(&mut self, additional: u8) -> Result<Cow<'de, str>> {
479        if additional == 31 {
480            // Indefinite-length text: concatenate definite chunks to break.
481            let mut out = String::new();
482            loop {
483                let b = self.header()?;
484                if b == 0xFF {
485                    break;
486                }
487                if b >> 5 != 3 {
488                    return Err(Error::custom(
489                        "cbor: indefinite text chunk must be a text string",
490                    ));
491                }
492                let chunk = self.read_text(b & 0x1F)?;
493                out.push_str(&chunk);
494            }
495            return Ok(Cow::Owned(out));
496        }
497        let len = usize::try_from(self.argument(additional)?)
498            .map_err(|_| Error::custom("cbor: text length exceeds platform limit"))?;
499        let bytes = self.cur.take(len)?;
500        let s = core::str::from_utf8(bytes)
501            .map_err(|_| Error::custom("cbor: invalid utf-8 in text"))?;
502        Ok(Cow::Borrowed(s))
503    }
504
505    fn read_bignum(&mut self, tag: u64) -> Result<Number> {
506        let b = self.header()?;
507        if b >> 5 != 2 || b & 0x1F == 31 {
508            return Err(Error::custom(
509                "cbor: bignum tag must be followed by a definite byte string",
510            ));
511        }
512        let len = usize::try_from(self.argument(b & 0x1F)?)
513            .map_err(|_| Error::custom("cbor: bignum magnitude too large"))?;
514        if len > 16 {
515            return Err(Error::custom("cbor: bignum exceeds 128 bits"));
516        }
517        let magnitude = self.cur.take(len)?;
518        let mut value: u128 = 0;
519        for &byte in magnitude {
520            value = (value << 8) | byte as u128;
521        }
522        if tag == 2 {
523            if value <= u64::MAX as u128 {
524                Ok(Number::U64(value as u64))
525            } else {
526                Ok(Number::U128(value))
527            }
528        } else if value <= i64::MAX as u128 {
529            Ok(Number::I64(-1 - value as i64))
530        } else if value <= i128::MAX as u128 {
531            Ok(Number::I128(-1 - value as i128))
532        } else {
533            Err(Error::custom("cbor: negative bignum exceeds i128"))
534        }
535    }
536
537    fn read_simple(&mut self, additional: u8) -> Result<Token<'de>> {
538        match additional {
539            20 => Ok(Token::Bool(false)),
540            21 => Ok(Token::Bool(true)),
541            22 => Ok(Token::Null),
542            25 => {
543                let value = half_to_f32(self.read_be_u16()?) as f64;
544                self.finite_float(value)
545            }
546            26 => {
547                let value = f32::from_bits(self.read_be_u32()?) as f64;
548                self.finite_float(value)
549            }
550            27 => {
551                let value = f64::from_bits(self.read_be_u64()?);
552                self.finite_float(value)
553            }
554            31 => Err(Error::custom("cbor: unexpected break marker")),
555            _ => Err(Error::custom("cbor: unsupported simple value")),
556        }
557    }
558
559    fn finite_float(&self, value: f64) -> Result<Token<'de>> {
560        if !value.is_finite() {
561            return Err(Error::custom(
562                "non-finite CBOR float is not representable in the JSON-compatible profile",
563            ));
564        }
565        Ok(Token::Number(Number::F64(value)))
566    }
567
568    /// Wrap a decoded float in a `Number`, rejecting non-finite values.
569    fn finite_number(&self, value: f64) -> Result<Number> {
570        if !value.is_finite() {
571            return Err(Error::custom(
572                "non-finite CBOR float is not representable in the JSON-compatible profile",
573            ));
574        }
575        Ok(Number::F64(value))
576    }
577
578    fn read_token(&mut self) -> Result<Token<'de>> {
579        let b = self.header()?;
580        let major = b >> 5;
581        let additional = b & 0x1F;
582        match major {
583            0 => Ok(Token::Number(Number::U64(self.argument(additional)?))),
584            1 => {
585                let argument = self.argument(additional)?;
586                let value = if argument <= i64::MAX as u64 {
587                    Number::I64(-1 - argument as i64)
588                } else {
589                    Number::I128(-1 - argument as i128)
590                };
591                Ok(Token::Number(value))
592            }
593            2 => Err(Error::custom(
594                "CBOR byte strings are not representable in the JSON-compatible profile",
595            )),
596            3 => Ok(Token::Str(self.read_text(additional)?)),
597            4 => {
598                self.pending = Some(DFrame {
599                    kind: FrameKind::Array,
600                    remaining: self.container_argument(additional)?,
601                });
602                Ok(Token::BeginArray)
603            }
604            5 => {
605                self.pending = Some(DFrame {
606                    kind: FrameKind::Map,
607                    remaining: self.container_argument(additional)?,
608                });
609                Ok(Token::BeginObject)
610            }
611            6 => {
612                let tag = self.argument(additional)?;
613                if tag != 2 && tag != 3 {
614                    return Err(Error::custom("cbor: unsupported semantic tag"));
615                }
616                Ok(Token::Number(self.read_bignum(tag)?))
617            }
618            7 => self.read_simple(additional),
619            _ => Err(Error::custom("cbor: invalid major type")),
620        }
621    }
622
623    fn take_pending(&mut self, kind: FrameKind) -> Result<DFrame> {
624        match self.pending.take() {
625            Some(frame) if frame.kind == kind => Ok(frame),
626            _ => Err(Error::custom("cbor: container header mismatch")),
627        }
628    }
629
630    /// Whether the next item in the current indefinite container is the
631    /// break marker (0xFF). Definite containers never inspect the wire here.
632    fn at_break(&mut self) -> Result<bool> {
633        if self.lookahead.is_some() {
634            return Ok(false);
635        }
636        Ok(self.cur.peek()? == 0xFF)
637    }
638}
639
640impl<'de> FormatDecoder<'de> for CborDecoder<'de> {
641    type Error = crate::error::Error;
642
643    fn begin_object(&mut self) -> Result<(), Self::Error> {
644        self.enter_container()?;
645        match self.next_token()? {
646            Token::BeginObject => {
647                let frame = self.take_pending(FrameKind::Map)?;
648                self.frames.push(frame);
649                Ok(())
650            }
651            other => Err(Error::invalid_type("a map", token_name(&other))),
652        }
653    }
654
655    fn end_object(&mut self) -> Result<(), Self::Error> {
656        let frame = self
657            .frames
658            .pop()
659            .ok_or_else(|| Error::custom("cbor: map end without start"))?;
660        match frame.remaining {
661            Some(0) => {}
662            Some(_) => return Err(Error::custom("cbor: map entry count mismatch")),
663            None => {
664                // Indefinite map: the break marker terminates it.
665                let b = self.header()?;
666                if b != 0xFF {
667                    return Err(Error::custom("cbor: indefinite map missing break"));
668                }
669            }
670        }
671        self.depth = self.depth.saturating_sub(1);
672        Ok(())
673    }
674
675    fn object_key(&mut self) -> Result<Option<Cow<'de, str>>, Self::Error> {
676        let frame = self
677            .frames
678            .last_mut()
679            .ok_or_else(|| Error::custom("cbor: object key outside map"))?;
680        match frame.remaining {
681            Some(0) => return Ok(None),
682            Some(n) => frame.remaining = Some(n - 1),
683            None => {
684                if self.at_break()? {
685                    return Ok(None);
686                }
687            }
688        }
689        let b = self.header()?;
690        if b >> 5 != 3 {
691            return Err(Error::custom("CBOR map key must be a text string"));
692        }
693        self.read_text(b & 0x1F).map(Some)
694    }
695
696    fn object_entry_sep(&mut self) -> Result<bool, Self::Error> {
697        let frame = self
698            .frames
699            .last()
700            .ok_or_else(|| Error::custom("cbor: object separator outside map"))?;
701        match frame.remaining {
702            Some(n) => Ok(n > 0),
703            None => Ok(!self.at_break()?),
704        }
705    }
706
707    fn begin_array(&mut self) -> Result<(), Self::Error> {
708        self.enter_container()?;
709        match self.next_token()? {
710            Token::BeginArray => {
711                let frame = self.take_pending(FrameKind::Array)?;
712                self.frames.push(frame);
713                Ok(())
714            }
715            other => Err(Error::invalid_type("an array", token_name(&other))),
716        }
717    }
718
719    fn end_array(&mut self) -> Result<(), Self::Error> {
720        let frame = self
721            .frames
722            .pop()
723            .ok_or_else(|| Error::custom("cbor: array end without start"))?;
724        match frame.remaining {
725            Some(0) => {}
726            Some(_) => return Err(Error::custom("cbor: array element count mismatch")),
727            None => {
728                let b = self.header()?;
729                if b != 0xFF {
730                    return Err(Error::custom("cbor: indefinite array missing break"));
731                }
732            }
733        }
734        self.depth = self.depth.saturating_sub(1);
735        Ok(())
736    }
737
738    fn array_has_more(&mut self) -> Result<bool, Self::Error> {
739        let frame = self
740            .frames
741            .last()
742            .ok_or_else(|| Error::custom("cbor: array check outside array"))?;
743        match frame.remaining {
744            Some(n) => Ok(n > 0),
745            None => Ok(!self.at_break()?),
746        }
747    }
748
749    fn array_entry_sep(&mut self) -> Result<bool, Self::Error> {
750        let frame = self
751            .frames
752            .last_mut()
753            .ok_or_else(|| Error::custom("cbor: array separator outside array"))?;
754        match frame.remaining {
755            Some(n) if n > 0 => {
756                frame.remaining = Some(n - 1);
757                Ok(n - 1 > 0)
758            }
759            Some(_) => Ok(false),
760            None => Ok(!self.at_break()?),
761        }
762    }
763
764    fn array_len_hint(&self) -> Option<usize> {
765        self.frames.last().and_then(|frame| {
766            (frame.kind == FrameKind::Array).then(|| {
767                usize::try_from(frame.remaining.unwrap_or(0))
768                    .unwrap_or(usize::MAX)
769                    .min(self.cur.remaining_len())
770                    .min(MAX_CONTAINER_PREALLOC)
771            })
772        })
773    }
774
775    fn object_len_hint(&self) -> Option<usize> {
776        self.frames.last().and_then(|frame| {
777            (frame.kind == FrameKind::Map).then(|| {
778                usize::try_from(frame.remaining.unwrap_or(0))
779                    .unwrap_or(usize::MAX)
780                    .min(self.cur.remaining_len())
781                    .min(MAX_CONTAINER_PREALLOC)
782            })
783        })
784    }
785
786    fn unit(&mut self) -> Result<(), Self::Error> {
787        // Byte-direct fast path: `null` is the single simple value 22 (0xF6).
788        if self.lookahead.is_none() {
789            match self.header()? {
790                0xF6 => return Ok(()),
791                _ => self.cur.rewind(1),
792            }
793        }
794        match self.next_token()? {
795            Token::Null => Ok(()),
796            other => Err(Error::invalid_type("null", token_name(&other))),
797        }
798    }
799
800    fn bool(&mut self) -> Result<bool, Self::Error> {
801        // Byte-direct fast path: `false` / `true` are simple values 20/21.
802        if self.lookahead.is_none() {
803            match self.header()? {
804                0xF4 => return Ok(false),
805                0xF5 => return Ok(true),
806                _ => self.cur.rewind(1),
807            }
808        }
809        match self.next_token()? {
810            Token::Bool(b) => Ok(b),
811            other => Err(Error::invalid_type("bool", token_name(&other))),
812        }
813    }
814
815    fn number(&mut self) -> Result<Number, Self::Error> {
816        // Byte-direct fast path: integers (major 0/1), bignums (tag 2/3) and
817        // floats (simple values 25/26/27) are read without a `Token`.
818        if self.lookahead.is_none() {
819            let b = self.header()?;
820            let major = b >> 5;
821            let additional = b & 0x1F;
822            match major {
823                0 => return Ok(Number::U64(self.argument(additional)?)),
824                1 => {
825                    let argument = self.argument(additional)?;
826                    return Ok(if argument <= i64::MAX as u64 {
827                        Number::I64(-1 - argument as i64)
828                    } else {
829                        Number::I128(-1 - argument as i128)
830                    });
831                }
832                6 => {
833                    let tag = self.argument(additional)?;
834                    if tag == 2 || tag == 3 {
835                        return self.read_bignum(tag);
836                    }
837                }
838                7 => match additional {
839                    25 => {
840                        let value = half_to_f32(self.read_be_u16()?) as f64;
841                        return self.finite_number(value);
842                    }
843                    26 => {
844                        let value = f32::from_bits(self.read_be_u32()?) as f64;
845                        return self.finite_number(value);
846                    }
847                    27 => {
848                        let value = f64::from_bits(self.read_be_u64()?);
849                        return self.finite_number(value);
850                    }
851                    _ => {}
852                },
853                _ => {}
854            }
855            self.cur.rewind(1);
856        }
857        match self.next_token()? {
858            Token::Number(n) => Ok(n),
859            other => Err(Error::invalid_type("number", token_name(&other))),
860        }
861    }
862
863    fn string(&mut self) -> Result<Cow<'de, str>, Self::Error> {
864        // Byte-direct fast path for text strings (major type 3).
865        if self.lookahead.is_none() {
866            let b = self.header()?;
867            if b >> 5 == 3 {
868                return self.read_text(b & 0x1F);
869            }
870            self.cur.rewind(1);
871        }
872        match self.next_token()? {
873            Token::Str(s) => Ok(s),
874            other => Err(Error::invalid_type("string", token_name(&other))),
875        }
876    }
877
878    fn char(&mut self) -> Result<char, Self::Error> {
879        match self.next_token()? {
880            Token::Str(s) => {
881                let mut chars = s.chars();
882                match (chars.next(), chars.next()) {
883                    (Some(c), None) => Ok(c),
884                    _ => Err(Error::invalid_type("a single-character string", "string")),
885                }
886            }
887            other => Err(Error::invalid_type("char", token_name(&other))),
888        }
889    }
890
891    fn skip_value(&mut self) -> Result<(), Self::Error> {
892        match self.peek_token()? {
893            Token::BeginObject => {
894                self.begin_object()?;
895                while self.object_key()?.is_some() {
896                    self.skip_value()?;
897                    if !self.object_entry_sep()? {
898                        break;
899                    }
900                }
901                self.end_object()
902            }
903            Token::BeginArray => {
904                self.begin_array()?;
905                while self.array_has_more()? {
906                    self.skip_value()?;
907                    if !self.array_entry_sep()? {
908                        break;
909                    }
910                }
911                self.end_array()
912            }
913            _ => {
914                self.next_token()?;
915                Ok(())
916            }
917        }
918    }
919
920    fn peek_token(&mut self) -> Result<Token<'de>, Self::Error> {
921        if self.lookahead.is_none() {
922            self.lookahead = Some(self.read_token()?);
923        }
924        self.lookahead
925            .clone()
926            .ok_or_else(|| Error::custom("cbor: lookahead unavailable"))
927    }
928
929    fn next_token(&mut self) -> Result<Token<'de>, Self::Error> {
930        if let Some(t) = self.lookahead.take() {
931            return Ok(t);
932        }
933        self.read_token()
934    }
935
936    fn save(&self) -> Mark {
937        Mark {
938            pos: self.cur.pos(),
939            depth: self.depth,
940            frame_len: self.frames.len(),
941        }
942    }
943
944    fn restore(&mut self, mark: Mark) {
945        self.cur.seek(mark.pos);
946        self.lookahead = None;
947        self.pending = None;
948        self.frames.truncate(mark.frame_len);
949        self.depth = mark.depth;
950    }
951
952    fn is_human_readable(&self) -> bool {
953        false
954    }
955}