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