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 {
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, opts.strictness),
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 {
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, opts.strictness),
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}