Skip to main content

cbor_core/
decoder.rs

1//! Iterators over CBOR sequences.
2//!
3//! [`SequenceDecoder`] iterates over an in-memory buffer; [`SequenceReader`]
4//! iterates over an `io::Read`. Both are produced by factory methods
5//! on [`DecodeOptions`](crate::DecodeOptions).
6
7use std::io;
8
9use crate::{
10    DecodeOptions, Format, IoResult, Result, Value,
11    io::{HexReader, HexSliceReader, PeekReader, SliceReader},
12    parse::Parser,
13};
14
15/// Iterator over a CBOR sequence stored in a byte slice.
16///
17/// Construct with [`SequenceDecoder::new`] for the crate defaults, or with
18/// [`DecodeOptions::sequence_decoder`] to choose an input format and decoding
19/// limits. Yields `Result<Value<'a>>` for each item, where `'a` is
20/// the lifetime of the input slice; in [`Format::Binary`] each item
21/// borrows text and byte strings directly from the slice. `next`
22/// returns `None` when the slice is fully consumed. For input from an
23/// `io::Read` source, use [`SequenceReader`] instead.
24///
25/// Sequence semantics depend on the format:
26///
27/// * [`Format::Binary`] and [`Format::Hex`]: items are concatenated with
28///   no separator. `next` returns `None` as soon as the buffer is fully
29///   consumed.
30/// * [`Format::Diagnostic`]: items are separated by a top-level comma
31///   and optional whitespace or comments. A trailing comma is
32///   accepted.
33///
34/// ```
35/// use cbor_core::SequenceDecoder;
36///
37/// // Binary CBOR sequence: three one-byte items.
38/// let items: Vec<_> = SequenceDecoder::new(&[0x01, 0x02, 0x03])
39///     .collect::<Result<_, _>>()
40///     .unwrap();
41/// assert_eq!(items.len(), 3);
42/// ```
43pub struct SequenceDecoder<'a> {
44    inner: SequenceDecoderInner<'a>,
45}
46
47enum SequenceDecoderInner<'a> {
48    Binary {
49        reader: SliceReader<'a>,
50        opts: DecodeOptions,
51    },
52    Hex {
53        reader: HexSliceReader<'a>,
54        opts: DecodeOptions,
55    },
56    Diagnostic {
57        parser: Parser<SliceReader<'a>>,
58    },
59}
60
61impl<'a> SequenceDecoder<'a> {
62    /// Decode a binary CBOR sequence from a byte slice.
63    ///
64    /// Shorthand for [`DecodeOptions::new().sequence_decoder(input)`](DecodeOptions::sequence_decoder),
65    /// so all limits use their defaults. Use the [`DecodeOptions`]
66    /// builder instead when you need hex or diagnostic input, or
67    /// want to adjust `recursion_limit`, `length_limit`, or
68    /// `oom_mitigation`.
69    ///
70    /// ```
71    /// use cbor_core::SequenceDecoder;
72    ///
73    /// let mut d = SequenceDecoder::new(&[0x01, 0x02]);
74    /// assert_eq!(d.next().unwrap().unwrap().to_u32().unwrap(), 1);
75    /// assert_eq!(d.next().unwrap().unwrap().to_u32().unwrap(), 2);
76    /// assert!(d.next().is_none());
77    /// ```
78    pub fn new<T>(input: &'a T) -> Self
79    where
80        T: AsRef<[u8]> + ?Sized,
81    {
82        Self::with_options(DecodeOptions::new(), input.as_ref())
83    }
84
85    pub(crate) fn with_options(opts: DecodeOptions, input: &'a [u8]) -> Self {
86        let inner = match opts.format_value() {
87            Format::Binary => SequenceDecoderInner::Binary {
88                reader: SliceReader(input),
89                opts,
90            },
91            Format::Hex => SequenceDecoderInner::Hex {
92                reader: HexSliceReader(input),
93                opts,
94            },
95            Format::Diagnostic => SequenceDecoderInner::Diagnostic {
96                parser: Parser::new(SliceReader(input), opts.recursion_limit_value()),
97            },
98        };
99        Self { inner }
100    }
101}
102
103impl<'a> Iterator for SequenceDecoder<'a> {
104    type Item = Result<Value<'a>>;
105
106    fn next(&mut self) -> Option<Self::Item> {
107        match &mut self.inner {
108            SequenceDecoderInner::Binary { reader, opts } => {
109                if reader.0.is_empty() {
110                    None
111                } else {
112                    Some(opts.decode_one(reader))
113                }
114            }
115            SequenceDecoderInner::Hex { reader, opts } => {
116                if reader.0.is_empty() {
117                    None
118                } else {
119                    Some(opts.decode_one(reader))
120                }
121            }
122            SequenceDecoderInner::Diagnostic { parser } => parser.parse_seq_item().transpose(),
123        }
124    }
125}
126
127/// Iterator over a CBOR sequence read from an [`io::Read`] source.
128///
129/// Construct with [`SequenceReader::new`] for the crate defaults, or with
130/// [`DecodeOptions::sequence_reader`] to choose an input format and
131/// decoding limits. Yields `IoResult<Value<'static>>` for each item:
132/// the bytes are read into an internal buffer, so each item is
133/// owned. `next` returns `None` when the stream ends at an item
134/// boundary; a truncated item returns
135/// `Some(Err(IoError::Data(Error::UnexpectedEof)))`. For in-memory
136/// input, use [`SequenceDecoder`] instead: it borrows from the input
137/// slice and returns plain `Result<Value<'_>>` without the I/O error
138/// arm.
139///
140/// Sequence semantics depend on the format:
141///
142/// * [`Format::Binary`] and [`Format::Hex`]: items are concatenated with
143///   no separator.
144/// * [`Format::Diagnostic`]: items are separated by a top-level comma
145///   and optional whitespace or comments. A trailing comma is
146///   accepted.
147///
148/// ```
149/// use cbor_core::SequenceReader;
150///
151/// let bytes: &[u8] = &[0x01, 0x02, 0x03];
152/// let items: Vec<_> = SequenceReader::new(bytes)
153///     .collect::<Result<_, _>>()
154///     .unwrap();
155/// assert_eq!(items.len(), 3);
156/// ```
157pub struct SequenceReader<R: io::Read> {
158    inner: SequenceReaderInner<R>,
159}
160
161enum SequenceReaderInner<R: io::Read> {
162    Binary {
163        reader: PeekReader<R>,
164        opts: DecodeOptions,
165    },
166    Hex {
167        reader: HexReader<PeekReader<R>>,
168        opts: DecodeOptions,
169    },
170    Diagnostic {
171        parser: Parser<R>,
172    },
173}
174
175impl<R: io::Read> SequenceReader<R> {
176    /// Decode a binary CBOR sequence from an [`io::Read`] source.
177    ///
178    /// Shorthand for [`DecodeOptions::new().sequence_reader(reader)`](DecodeOptions::sequence_reader),
179    /// so all limits use their defaults. Use the [`DecodeOptions`]
180    /// builder instead when you need hex or diagnostic input, or
181    /// want to adjust `recursion_limit`, `length_limit`, or
182    /// `oom_mitigation`.
183    ///
184    /// ```
185    /// use cbor_core::SequenceReader;
186    ///
187    /// let bytes: &[u8] = &[0x01, 0x02];
188    /// let mut s = SequenceReader::new(bytes);
189    /// assert_eq!(s.next().unwrap().unwrap().to_u32().unwrap(), 1);
190    /// assert_eq!(s.next().unwrap().unwrap().to_u32().unwrap(), 2);
191    /// assert!(s.next().is_none());
192    /// ```
193    pub fn new(reader: R) -> Self {
194        Self::with_options(DecodeOptions::new(), reader)
195    }
196
197    pub(crate) fn with_options(opts: DecodeOptions, reader: R) -> Self {
198        let inner = match opts.format_value() {
199            Format::Binary => SequenceReaderInner::Binary {
200                reader: PeekReader::new(reader),
201                opts,
202            },
203            Format::Hex => SequenceReaderInner::Hex {
204                reader: HexReader(PeekReader::new(reader)),
205                opts,
206            },
207            Format::Diagnostic => SequenceReaderInner::Diagnostic {
208                parser: Parser::new(reader, opts.recursion_limit_value()),
209            },
210        };
211        Self { inner }
212    }
213}
214
215impl<R: io::Read> Iterator for SequenceReader<R> {
216    type Item = IoResult<Value<'static>>;
217
218    fn next(&mut self) -> Option<Self::Item> {
219        match &mut self.inner {
220            SequenceReaderInner::Binary { reader, opts } => match reader.at_eof() {
221                Ok(true) => None,
222                Ok(false) => Some(opts.decode_one(reader)),
223                Err(error) => Some(Err(error)),
224            },
225            SequenceReaderInner::Hex { reader, opts } => match reader.0.at_eof() {
226                Ok(true) => None,
227                Ok(false) => Some(opts.decode_one(reader)),
228                Err(error) => Some(Err(error)),
229            },
230            SequenceReaderInner::Diagnostic { parser } => parser.parse_seq_item().transpose(),
231        }
232    }
233}