1 use super::*;
2 
3 use ciborium_io::Read;
4 
5 /// An error that occurred while decoding
6 #[derive(Debug)]
7 pub enum Error<T> {
8     /// An error occurred while reading bytes
9     ///
10     /// Contains the underlying error returned while reading.
11     Io(T),
12 
13     /// An error occurred while parsing bytes
14     ///
15     /// Contains the offset into the stream where the syntax error occurred.
16     Syntax(usize),
17 }
18 
19 impl<T> From<T> for Error<T> {
20     #[inline]
from(value: T) -> Self21     fn from(value: T) -> Self {
22         Self::Io(value)
23     }
24 }
25 
26 /// A decoder for deserializing CBOR items
27 ///
28 /// This decoder manages the low-level decoding of CBOR items into `Header`
29 /// objects. It also contains utility functions for parsing segmented bytes
30 /// and text inputs.
31 pub struct Decoder<R: Read> {
32     reader: R,
33     offset: usize,
34     buffer: Option<Title>,
35 }
36 
37 impl<R: Read> From<R> for Decoder<R> {
38     #[inline]
from(value: R) -> Self39     fn from(value: R) -> Self {
40         Self {
41             reader: value,
42             offset: 0,
43             buffer: None,
44         }
45     }
46 }
47 
48 impl<R: Read> Read for Decoder<R> {
49     type Error = R::Error;
50 
51     #[inline]
read_exact(&mut self, data: &mut [u8]) -> Result<(), Self::Error>52     fn read_exact(&mut self, data: &mut [u8]) -> Result<(), Self::Error> {
53         assert!(self.buffer.is_none());
54         self.reader.read_exact(data)?;
55         self.offset += data.len();
56         Ok(())
57     }
58 }
59 
60 impl<R: Read> Decoder<R> {
61     #[inline]
pull_title(&mut self) -> Result<Title, Error<R::Error>>62     fn pull_title(&mut self) -> Result<Title, Error<R::Error>> {
63         if let Some(title) = self.buffer.take() {
64             self.offset += title.1.as_ref().len() + 1;
65             return Ok(title);
66         }
67 
68         let mut prefix = [0u8; 1];
69         self.read_exact(&mut prefix[..])?;
70 
71         let major = match prefix[0] >> 5 {
72             0 => Major::Positive,
73             1 => Major::Negative,
74             2 => Major::Bytes,
75             3 => Major::Text,
76             4 => Major::Array,
77             5 => Major::Map,
78             6 => Major::Tag,
79             7 => Major::Other,
80             _ => unreachable!(),
81         };
82 
83         let mut minor = match prefix[0] & 0b00011111 {
84             x if x < 24 => Minor::This(x),
85             24 => Minor::Next1([0; 1]),
86             25 => Minor::Next2([0; 2]),
87             26 => Minor::Next4([0; 4]),
88             27 => Minor::Next8([0; 8]),
89             31 => Minor::More,
90             _ => return Err(Error::Syntax(self.offset - 1)),
91         };
92 
93         self.read_exact(minor.as_mut())?;
94         Ok(Title(major, minor))
95     }
96 
97     #[inline]
push_title(&mut self, item: Title)98     fn push_title(&mut self, item: Title) {
99         assert!(self.buffer.is_none());
100         self.buffer = Some(item);
101         self.offset -= item.1.as_ref().len() + 1;
102     }
103 
104     /// Pulls the next header from the input
105     #[inline]
pull(&mut self) -> Result<Header, Error<R::Error>>106     pub fn pull(&mut self) -> Result<Header, Error<R::Error>> {
107         let offset = self.offset;
108         self.pull_title()?
109             .try_into()
110             .map_err(|_| Error::Syntax(offset))
111     }
112 
113     /// Push a single header into the input buffer
114     ///
115     /// # Panics
116     ///
117     /// This function panics if called while there is already a header in the
118     /// input buffer. You should take care to call this function only after
119     /// pulling a header to ensure there is nothing in the input buffer.
120     #[inline]
push(&mut self, item: Header)121     pub fn push(&mut self, item: Header) {
122         self.push_title(Title::from(item))
123     }
124 
125     /// Gets the current byte offset into the stream
126     ///
127     /// The offset starts at zero when the decoder is created. Therefore, if
128     /// bytes were already read from the reader before the decoder was created,
129     /// you must account for this.
130     #[inline]
offset(&mut self) -> usize131     pub fn offset(&mut self) -> usize {
132         self.offset
133     }
134 
135     /// Process an incoming bytes item
136     ///
137     /// In CBOR, bytes can be segmented. The logic for this can be a bit tricky,
138     /// so we encapsulate that logic using this function. This function **MUST**
139     /// be called immediately after first pulling a `Header::Bytes(len)` from
140     /// the wire and `len` must be provided to this function from that value.
141     ///
142     /// The `buf` parameter provides a buffer used when reading in the segmented
143     /// bytes. A large buffer will result in fewer calls to read incoming bytes
144     /// at the cost of memory usage. You should consider this trade off when
145     /// deciding the size of your buffer.
146     #[inline]
bytes(&mut self, len: Option<usize>) -> Segments<R, crate::seg::Bytes>147     pub fn bytes(&mut self, len: Option<usize>) -> Segments<R, crate::seg::Bytes> {
148         self.push(Header::Bytes(len));
149         Segments::new(self, |header| match header {
150             Header::Bytes(len) => Ok(len),
151             _ => Err(()),
152         })
153     }
154 
155     /// Process an incoming text item
156     ///
157     /// In CBOR, text can be segmented. The logic for this can be a bit tricky,
158     /// so we encapsulate that logic using this function. This function **MUST**
159     /// be called immediately after first pulling a `Header::Text(len)` from
160     /// the wire and `len` must be provided to this function from that value.
161     ///
162     /// The `buf` parameter provides a buffer used when reading in the segmented
163     /// text. A large buffer will result in fewer calls to read incoming bytes
164     /// at the cost of memory usage. You should consider this trade off when
165     /// deciding the size of your buffer.
166     #[inline]
text(&mut self, len: Option<usize>) -> Segments<R, crate::seg::Text>167     pub fn text(&mut self, len: Option<usize>) -> Segments<R, crate::seg::Text> {
168         self.push(Header::Text(len));
169         Segments::new(self, |header| match header {
170             Header::Text(len) => Ok(len),
171             _ => Err(()),
172         })
173     }
174 }
175