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