Skip to main content

deser_cbor/
stream.rs

1//! Reading CBOR streams.
2#[cfg(feature = "io")]
3use std::io::Read;
4
5use alloc::vec::Vec;
6#[cfg(feature = "io")]
7use deser_core::de::DeserializeOwned;
8use deser_core::de::{self, DeserializeDriver, Frame, Progress};
9use deser_core::{Error, ErrorKind, State};
10
11use crate::de::{Deserializer, DeserializerConfig};
12use crate::parser::{Copying, Discard, Parser, Progress as ParseProgress};
13
14const MAJOR_BYTES: u8 = 2;
15const MAJOR_TEXT: u8 = 3;
16const MAJOR_ARRAY: u8 = 4;
17const MAJOR_MAP: u8 = 5;
18const MAJOR_TAG: u8 = 6;
19const MAJOR_SIMPLE: u8 = 7;
20const INDEFINITE: u8 = 31;
21
22/// The state of a CBOR stream that is read.
23#[derive(Default)]
24struct StreamState {
25    // the position up to which the item was scanned
26    pos: usize,
27    // the number of items the open containers (and tags) still need, `None`
28    // for indefinite lengths.
29    stack: Vec<Option<u64>>,
30    // an item was not well-formed
31    failed: bool,
32    // parses items while their input arrives (see `drive_partial`)
33    parser: Parser,
34    // the driver of the current item was set up
35    started: bool,
36    // the rest of an item that failed in a sink is skipped from the
37    // position in the input
38    skipping: Option<usize>,
39    // parsing failed, the stream cannot be continued
40    partial_failed: bool,
41    // the stream ended within an item
42    ended: bool,
43}
44
45impl core::fmt::Debug for StreamState {
46    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
47        f.debug_struct("StreamState").finish_non_exhaustive()
48    }
49}
50
51/// The result of scanning an item.
52enum Scan {
53    /// The item ends at the given offset.
54    Complete(usize),
55    /// More input is needed.
56    Incomplete,
57    /// The item is not well-formed at the given offset.
58    Malformed(usize),
59}
60
61impl StreamState {
62    /// Scans the item from the current position.
63    fn scan(&mut self, input: &[u8]) -> Scan {
64        loop {
65            let head_start = self.pos;
66            let Some(&initial) = input.get(head_start) else {
67                return Scan::Incomplete;
68            };
69            let major = initial >> 5;
70            let info = initial & 0x1f;
71            let arg_len = match info {
72                0..=23 => 0,
73                24 => 1,
74                25 => 2,
75                26 => 4,
76                27 => 8,
77                INDEFINITE => 0,
78                _ => return Scan::Malformed(head_start),
79            };
80            let Some(arg_bytes) = input.get(head_start + 1..head_start + 1 + arg_len) else {
81                return Scan::Incomplete;
82            };
83            let arg = if info < 24 {
84                u64::from(info)
85            } else {
86                arg_bytes
87                    .iter()
88                    .fold(0u64, |acc, &b| (acc << 8) | u64::from(b))
89            };
90            let mut pos = head_start + 1 + arg_len;
91
92            let item_done = if info == INDEFINITE {
93                match major {
94                    MAJOR_BYTES | MAJOR_TEXT | MAJOR_ARRAY | MAJOR_MAP => {
95                        self.stack.push(None);
96                        false
97                    }
98                    // the end of an indefinite length item
99                    MAJOR_SIMPLE => match self.stack.pop() {
100                        Some(None) => true,
101                        _ => return Scan::Malformed(head_start),
102                    },
103                    _ => return Scan::Malformed(head_start),
104                }
105            } else {
106                match major {
107                    MAJOR_BYTES | MAJOR_TEXT => {
108                        let end = usize::try_from(arg)
109                            .ok()
110                            .and_then(|len| pos.checked_add(len));
111                        match end {
112                            Some(end) if end <= input.len() => pos = end,
113                            Some(_) => return Scan::Incomplete,
114                            None => return Scan::Malformed(head_start),
115                        }
116                        true
117                    }
118                    MAJOR_ARRAY | MAJOR_MAP | MAJOR_TAG => {
119                        let items = match major {
120                            MAJOR_MAP => match arg.checked_mul(2) {
121                                Some(items) => items,
122                                None => return Scan::Malformed(head_start),
123                            },
124                            MAJOR_TAG => 1,
125                            _ => arg,
126                        };
127                        if items == 0 {
128                            true
129                        } else {
130                            self.stack.push(Some(items));
131                            false
132                        }
133                    }
134                    _ => true,
135                }
136            };
137            self.pos = pos;
138
139            if item_done {
140                // account for the item in the containers it completes
141                loop {
142                    match self.stack.last_mut() {
143                        None => return Scan::Complete(pos),
144                        Some(None) => break,
145                        Some(Some(remaining)) => {
146                            *remaining -= 1;
147                            if *remaining > 0 {
148                                break;
149                            }
150                            self.stack.pop();
151                        }
152                    }
153                }
154            }
155        }
156    }
157}
158
159/// Reads a stream of CBOR data items into items (see [`deser::stream`](deser_core::stream)).
160///
161/// The stream is a [CBOR sequence](https://www.rfc-editor.org/rfc/rfc8742)
162/// of data items that follow each other.  An item is complete once its last
163/// byte was read.  Reading continues after items that fail to deserialize,
164/// items that are not well-formed end the stream.
165///
166/// Items which do not borrow are deserialized while their input arrives
167/// (see
168/// [`StreamDeserializer::drive_partial`](de::StreamDeserializer::drive_partial))
169/// so only incomplete data items (like strings) are buffered.
170///
171/// ```
172/// # #[cfg(feature = "io")] {
173/// use deser_cbor::DeserializerConfig;
174///
175/// let mut reader =
176///     DeserializerConfig::new().reader(&[0x01, 0x62, b'h', b'i'][..]);
177/// assert_eq!(reader.read::<u32>().unwrap(), Some(1));
178/// assert_eq!(reader.read::<String>().unwrap().as_deref(), Some("hi"));
179/// assert_eq!(reader.read::<u32>().unwrap(), None);
180/// # }
181/// ```
182///
183/// Items are parsed like with a [`Deserializer`], so they can borrow from
184/// the stream's buffer (see
185/// [`InputBuffer::deserialize`](deser_core::stream::InputBuffer::deserialize)).
186#[derive(Debug)]
187pub struct StreamDeserializer {
188    config: DeserializerConfig,
189    state: StreamState,
190}
191
192impl Default for StreamDeserializer {
193    fn default() -> StreamDeserializer {
194        StreamDeserializer::new()
195    }
196}
197
198impl StreamDeserializer {
199    /// Creates a stream deserializer.
200    pub fn new() -> StreamDeserializer {
201        StreamDeserializer::with_config(DeserializerConfig::new())
202    }
203
204    /// Creates a stream deserializer with the given configuration.
205    pub fn with_config(config: DeserializerConfig) -> StreamDeserializer {
206        StreamDeserializer {
207            config,
208            state: StreamState::default(),
209        }
210    }
211
212    /// Returns the configuration.
213    pub fn config(&self) -> &DeserializerConfig {
214        &self.config
215    }
216
217    /// Skips the rest of an item that failed in a sink.
218    ///
219    /// Returns where the next item starts, or the progress if there is no
220    /// item (yet).
221    fn skip_to_item(
222        &mut self,
223        input: &[u8],
224        offset: usize,
225        eof: bool,
226    ) -> Result<Result<usize, Progress>, Error> {
227        let state = &mut self.state;
228        if state.ended {
229            return Ok(Err(Progress::End));
230        }
231        if state.partial_failed {
232            return Err(Error::new(
233                ErrorKind::InvalidState,
234                "cannot continue after an error",
235            ));
236        }
237
238        // skip the rest of an item that failed in a sink
239        let mut pos = 0;
240        if let Some(skip) = state.skipping {
241            let mut discard = Discard(State::new());
242            match state.parser.parse(input, skip, eof, offset, &mut discard) {
243                Ok(ParseProgress::Done(end)) => {
244                    state.skipping = None;
245                    pos = end;
246                }
247                Ok(ParseProgress::NeedMore(consumed)) => {
248                    state.skipping = Some(0);
249                    return Ok(Err(Progress::NeedMore { consumed }));
250                }
251                Err(err) => {
252                    state.skipping = None;
253                    return Err(fail(state, err, eof));
254                }
255            }
256        }
257
258        if !state.started && pos == input.len() {
259            return Ok(Err(if eof {
260                Progress::End
261            } else {
262                Progress::NeedMore { consumed: pos }
263            }));
264        }
265        Ok(Ok(pos))
266    }
267}
268
269impl de::StreamDeserializer for StreamDeserializer {
270    fn context(&self) -> deser_core::Context {
271        self.config.context().clone()
272    }
273
274    fn frame(&mut self, input: &[u8], eof: bool) -> Result<Frame, Error> {
275        let state = &mut self.state;
276        if state.failed {
277            return Err(Error::new(
278                ErrorKind::InvalidState,
279                "cannot continue after an item that is not well-formed",
280            ));
281        }
282        if input.is_empty() && eof {
283            return Ok(Frame::End);
284        }
285        let end = match state.scan(input) {
286            Scan::Complete(end) => end,
287            Scan::Incomplete if !eof => return Ok(Frame::Incomplete { consumed: 0 }),
288            // the parser reports the error
289            Scan::Incomplete => input.len(),
290            Scan::Malformed(offset) => {
291                state.failed = true;
292                offset + 1
293            }
294        };
295        state.pos = 0;
296        state.stack.clear();
297        Ok(Frame::Value {
298            start: 0,
299            end,
300            consumed: end,
301        })
302    }
303
304    fn drive_frame<'de>(
305        &mut self,
306        frame: &'de [u8],
307        driver: &mut DeserializeDriver<'_, 'de>,
308    ) -> Result<(), Error> {
309        let mut de = Deserializer::from_slice_with_config(frame, self.config.without_context());
310        de.drive(driver)?;
311        de.end()
312    }
313
314    fn supports_partial(&self) -> bool {
315        true
316    }
317
318    fn drive_partial(
319        &mut self,
320        input: &[u8],
321        offset: usize,
322        eof: bool,
323        driver: &mut DeserializeDriver<'_, '_>,
324    ) -> Result<Progress, Error> {
325        let pos = match self.skip_to_item(input, offset, eof)? {
326            Ok(pos) => pos,
327            Err(progress) => return Ok(progress),
328        };
329        let state = &mut self.state;
330        state.started = true;
331        match state
332            .parser
333            .parse(input, pos, eof, offset, &mut Copying(driver))
334        {
335            Ok(ParseProgress::Done(end)) => {
336                state.started = false;
337                Ok(Progress::Done { consumed: end })
338            }
339            Ok(ParseProgress::NeedMore(consumed)) => Ok(Progress::NeedMore { consumed }),
340            Err(err) => {
341                state.started = false;
342                match state.parser.recoverable() {
343                    // a sink failed, the next call continues after the
344                    // item.  The input is not consumed on errors.
345                    Some(resume) => {
346                        state.skipping = Some(resume);
347                        Err(err)
348                    }
349                    None => Err(fail(state, err, eof)),
350                }
351            }
352        }
353    }
354
355    fn peek(&mut self, input: &[u8], eof: bool) -> Result<Option<Progress>, Error> {
356        Ok(Some(match self.skip_to_item(input, 0, eof)? {
357            Ok(pos) => Progress::Done { consumed: pos },
358            Err(progress) => progress,
359        }))
360    }
361}
362
363#[cfg(feature = "io")]
364impl DeserializerConfig {
365    /// Creates a reader of a stream of data items (see
366    /// [`deser::io::Reader`](deser_core::io::Reader)).
367    ///
368    /// See [`StreamDeserializer`] for how the stream is read.
369    pub fn reader<R: Read>(&self, reader: R) -> deser_core::io::Reader<R, StreamDeserializer> {
370        deser_core::io::Reader::new(reader, StreamDeserializer::with_config(self.clone()))
371    }
372
373    /// Deserializes a data item from a reader.
374    ///
375    /// See [`from_reader`].
376    pub fn from_reader<T: DeserializeOwned, R: Read>(&self, reader: R) -> Result<T, Error> {
377        deser_core::io::from_reader(reader, StreamDeserializer::with_config(self.clone()))
378    }
379}
380
381/// Deserializes a data item from a reader.
382///
383/// The reader is read to the end, no data may follow the item.  The reader
384/// does not need to be buffered.  To read more than one item (a CBOR
385/// sequence) use [`DeserializerConfig::reader`].
386///
387/// ```
388/// let value: Vec<u32> =
389///     deser_cbor::from_reader(&[0x82, 0x01, 0x02][..]).unwrap();
390/// assert_eq!(value, [1, 2]);
391/// ```
392#[cfg(feature = "io")]
393pub fn from_reader<T: DeserializeOwned, R: Read>(reader: R) -> Result<T, Error> {
394    DeserializerConfig::new().from_reader(reader)
395}
396
397/// Ends the stream after an error that cannot be recovered from.
398fn fail(state: &mut StreamState, err: Error, eof: bool) -> Error {
399    state.parser.reset();
400    state.partial_failed = true;
401    // after an incomplete item at the end there are no more items
402    state.ended = eof && err.kind() == ErrorKind::EndOfFile;
403    err
404}