diff options
Diffstat (limited to 'third_party/rust/serde_cbor/src/read.rs')
-rw-r--r-- | third_party/rust/serde_cbor/src/read.rs | 637 |
1 files changed, 637 insertions, 0 deletions
diff --git a/third_party/rust/serde_cbor/src/read.rs b/third_party/rust/serde_cbor/src/read.rs new file mode 100644 index 0000000000..1b53018df8 --- /dev/null +++ b/third_party/rust/serde_cbor/src/read.rs @@ -0,0 +1,637 @@ +#[cfg(feature = "alloc")] +use alloc::{vec, vec::Vec}; +#[cfg(feature = "std")] +use core::cmp; +use core::mem; + +#[cfg(feature = "std")] +use std::io::{self, Read as StdRead}; + +use crate::error::{Error, ErrorCode, Result}; + +#[cfg(not(feature = "unsealed_read_write"))] +/// Trait used by the deserializer for iterating over input. +/// +/// This trait is sealed by default, enabling the `unsealed_read_write` feature removes this bound +/// to allow objects outside of this crate to implement this trait. +pub trait Read<'de>: private::Sealed { + #[doc(hidden)] + /// Read n bytes from the input. + /// + /// Implementations that can are asked to return a slice with a Long lifetime that outlives the + /// decoder, but others (eg. ones that need to allocate the data into a temporary buffer) can + /// return it with a Short lifetime that just lives for the time of read's mutable borrow of + /// the reader. + /// + /// This may, as a side effect, clear the reader's scratch buffer (as the provided + /// implementation does). + + // A more appropriate lifetime setup for this (that would allow the Deserializer::convert_str + // to stay a function) would be something like `fn read<'a, 'r: 'a>(&'a mut 'r immut self, ...) -> ... + // EitherLifetime<'r, 'de>>`, which borrows self mutably for the duration of the function and + // downgrates that reference to an immutable one that outlives the result (protecting the + // scratch buffer from changes), but alas, that can't be expressed (yet?). + fn read<'a>(&'a mut self, n: usize) -> Result<EitherLifetime<'a, 'de>> { + self.clear_buffer(); + self.read_to_buffer(n)?; + + Ok(self.take_buffer()) + } + + #[doc(hidden)] + fn next(&mut self) -> Result<Option<u8>>; + + #[doc(hidden)] + fn peek(&mut self) -> Result<Option<u8>>; + + #[doc(hidden)] + fn clear_buffer(&mut self); + + #[doc(hidden)] + fn read_to_buffer(&mut self, n: usize) -> Result<()>; + + #[doc(hidden)] + fn take_buffer<'a>(&'a mut self) -> EitherLifetime<'a, 'de>; + + #[doc(hidden)] + fn read_into(&mut self, buf: &mut [u8]) -> Result<()>; + + #[doc(hidden)] + fn discard(&mut self); + + #[doc(hidden)] + fn offset(&self) -> u64; +} + +#[cfg(feature = "unsealed_read_write")] +/// Trait used by the deserializer for iterating over input. +pub trait Read<'de> { + /// Read n bytes from the input. + /// + /// Implementations that can are asked to return a slice with a Long lifetime that outlives the + /// decoder, but others (eg. ones that need to allocate the data into a temporary buffer) can + /// return it with a Short lifetime that just lives for the time of read's mutable borrow of + /// the reader. + /// + /// This may, as a side effect, clear the reader's scratch buffer (as the provided + /// implementation does). + + // A more appropriate lifetime setup for this (that would allow the Deserializer::convert_str + // to stay a function) would be something like `fn read<'a, 'r: 'a>(&'a mut 'r immut self, ...) -> ... + // EitherLifetime<'r, 'de>>`, which borrows self mutably for the duration of the function and + // downgrates that reference to an immutable one that outlives the result (protecting the + // scratch buffer from changes), but alas, that can't be expressed (yet?). + fn read<'a>(&'a mut self, n: usize) -> Result<EitherLifetime<'a, 'de>> { + self.clear_buffer(); + self.read_to_buffer(n)?; + + Ok(self.take_buffer()) + } + + /// Read the next byte from the input, if any. + fn next(&mut self) -> Result<Option<u8>>; + + /// Peek at the next byte of the input, if any. This does not advance the reader, so the result + /// of this function will remain the same until a read or clear occurs. + fn peek(&mut self) -> Result<Option<u8>>; + + /// Clear the underlying scratch buffer + fn clear_buffer(&mut self); + + /// Append n bytes from the reader to the reader's scratch buffer (without clearing it) + fn read_to_buffer(&mut self, n: usize) -> Result<()>; + + /// Read out everything accumulated in the reader's scratch buffer. This may, as a side effect, + /// clear it. + fn take_buffer<'a>(&'a mut self) -> EitherLifetime<'a, 'de>; + + /// Read from the input until `buf` is full or end of input is encountered. + fn read_into(&mut self, buf: &mut [u8]) -> Result<()>; + + /// Discard any data read by `peek`. + fn discard(&mut self); + + /// Returns the offset from the start of the reader. + fn offset(&self) -> u64; +} + +/// Represents a reader that can return its current position +pub trait Offset { + fn byte_offset(&self) -> usize; +} + +/// Represents a buffer with one of two lifetimes. +pub enum EitherLifetime<'short, 'long> { + /// The short lifetime + Short(&'short [u8]), + /// The long lifetime + Long(&'long [u8]), +} + +#[cfg(not(feature = "unsealed_read_write"))] +mod private { + pub trait Sealed {} +} + +/// CBOR input source that reads from a std::io input stream. +#[cfg(feature = "std")] +#[derive(Debug)] +pub struct IoRead<R> +where + R: io::Read, +{ + reader: OffsetReader<R>, + scratch: Vec<u8>, + ch: Option<u8>, +} + +#[cfg(feature = "std")] +impl<R> IoRead<R> +where + R: io::Read, +{ + /// Creates a new CBOR input source to read from a std::io input stream. + pub fn new(reader: R) -> IoRead<R> { + IoRead { + reader: OffsetReader { reader, offset: 0 }, + scratch: vec![], + ch: None, + } + } + + #[inline] + fn next_inner(&mut self) -> Result<Option<u8>> { + let mut buf = [0; 1]; + loop { + match self.reader.read(&mut buf) { + Ok(0) => return Ok(None), + Ok(_) => return Ok(Some(buf[0])), + Err(ref e) if e.kind() == io::ErrorKind::Interrupted => {} + Err(e) => return Err(Error::io(e)), + } + } + } +} + +#[cfg(all(feature = "std", not(feature = "unsealed_read_write")))] +impl<R> private::Sealed for IoRead<R> where R: io::Read {} + +#[cfg(feature = "std")] +impl<'de, R> Read<'de> for IoRead<R> +where + R: io::Read, +{ + #[inline] + fn next(&mut self) -> Result<Option<u8>> { + match self.ch.take() { + Some(ch) => Ok(Some(ch)), + None => self.next_inner(), + } + } + + #[inline] + fn peek(&mut self) -> Result<Option<u8>> { + match self.ch { + Some(ch) => Ok(Some(ch)), + None => { + self.ch = self.next_inner()?; + Ok(self.ch) + } + } + } + + fn read_to_buffer(&mut self, mut n: usize) -> Result<()> { + // defend against malicious input pretending to be huge strings by limiting growth + self.scratch.reserve(cmp::min(n, 16 * 1024)); + + if n == 0 { + return Ok(()); + } + + if let Some(ch) = self.ch.take() { + self.scratch.push(ch); + n -= 1; + } + + // n == 0 is OK here and needs no further special treatment + + let transfer_result = { + // Prepare for take() (which consumes its reader) by creating a reference adaptor + // that'll only live in this block + let reference = self.reader.by_ref(); + // Append the first n bytes of the reader to the scratch vector (or up to + // an error or EOF indicated by a shorter read) + let mut taken = reference.take(n as u64); + taken.read_to_end(&mut self.scratch) + }; + + match transfer_result { + Ok(r) if r == n => Ok(()), + Ok(_) => Err(Error::syntax( + ErrorCode::EofWhileParsingValue, + self.offset(), + )), + Err(e) => Err(Error::io(e)), + } + } + + fn clear_buffer(&mut self) { + self.scratch.clear(); + } + + fn take_buffer<'a>(&'a mut self) -> EitherLifetime<'a, 'de> { + EitherLifetime::Short(&self.scratch) + } + + fn read_into(&mut self, buf: &mut [u8]) -> Result<()> { + self.reader.read_exact(buf).map_err(|e| { + if e.kind() == io::ErrorKind::UnexpectedEof { + Error::syntax(ErrorCode::EofWhileParsingValue, self.offset()) + } else { + Error::io(e) + } + }) + } + + #[inline] + fn discard(&mut self) { + self.ch = None; + } + + fn offset(&self) -> u64 { + self.reader.offset + } +} + +#[cfg(feature = "std")] +impl<R> Offset for IoRead<R> +where + R: std::io::Read, +{ + fn byte_offset(&self) -> usize { + self.offset() as usize + } +} + +#[cfg(feature = "std")] +#[derive(Debug)] +struct OffsetReader<R> { + reader: R, + offset: u64, +} + +#[cfg(feature = "std")] +impl<R> io::Read for OffsetReader<R> +where + R: io::Read, +{ + #[inline] + fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> { + let r = self.reader.read(buf); + if let Ok(count) = r { + self.offset += count as u64; + } + r + } +} + +/// A CBOR input source that reads from a slice of bytes. +#[cfg(any(feature = "std", feature = "alloc"))] +#[derive(Debug)] +pub struct SliceRead<'a> { + slice: &'a [u8], + scratch: Vec<u8>, + index: usize, +} + +#[cfg(any(feature = "std", feature = "alloc"))] +impl<'a> SliceRead<'a> { + /// Creates a CBOR input source to read from a slice of bytes. + pub fn new(slice: &'a [u8]) -> SliceRead<'a> { + SliceRead { + slice, + scratch: vec![], + index: 0, + } + } + + fn end(&self, n: usize) -> Result<usize> { + match self.index.checked_add(n) { + Some(end) if end <= self.slice.len() => Ok(end), + _ => Err(Error::syntax( + ErrorCode::EofWhileParsingValue, + self.slice.len() as u64, + )), + } + } +} + +#[cfg(any(feature = "std", feature = "alloc"))] +impl<'a> Offset for SliceRead<'a> { + #[inline] + fn byte_offset(&self) -> usize { + self.index + } +} + +#[cfg(all( + any(feature = "std", feature = "alloc"), + not(feature = "unsealed_read_write") +))] +impl<'a> private::Sealed for SliceRead<'a> {} + +#[cfg(any(feature = "std", feature = "alloc"))] +impl<'a> Read<'a> for SliceRead<'a> { + #[inline] + fn next(&mut self) -> Result<Option<u8>> { + Ok(if self.index < self.slice.len() { + let ch = self.slice[self.index]; + self.index += 1; + Some(ch) + } else { + None + }) + } + + #[inline] + fn peek(&mut self) -> Result<Option<u8>> { + Ok(if self.index < self.slice.len() { + Some(self.slice[self.index]) + } else { + None + }) + } + + fn clear_buffer(&mut self) { + self.scratch.clear(); + } + + fn read_to_buffer(&mut self, n: usize) -> Result<()> { + let end = self.end(n)?; + let slice = &self.slice[self.index..end]; + self.scratch.extend_from_slice(slice); + self.index = end; + + Ok(()) + } + + #[inline] + fn read<'b>(&'b mut self, n: usize) -> Result<EitherLifetime<'b, 'a>> { + let end = self.end(n)?; + let slice = &self.slice[self.index..end]; + self.index = end; + Ok(EitherLifetime::Long(slice)) + } + + fn take_buffer<'b>(&'b mut self) -> EitherLifetime<'b, 'a> { + EitherLifetime::Short(&self.scratch) + } + + #[inline] + fn read_into(&mut self, buf: &mut [u8]) -> Result<()> { + let end = self.end(buf.len())?; + buf.copy_from_slice(&self.slice[self.index..end]); + self.index = end; + Ok(()) + } + + #[inline] + fn discard(&mut self) { + self.index += 1; + } + + fn offset(&self) -> u64 { + self.index as u64 + } +} + +/// A CBOR input source that reads from a slice of bytes using a fixed size scratch buffer. +/// +/// [`SliceRead`](struct.SliceRead.html) and [`MutSliceRead`](struct.MutSliceRead.html) are usually +/// preferred over this, as they can handle indefinite length items. +#[derive(Debug)] +pub struct SliceReadFixed<'a, 'b> { + slice: &'a [u8], + scratch: &'b mut [u8], + index: usize, + scratch_index: usize, +} + +impl<'a, 'b> SliceReadFixed<'a, 'b> { + /// Creates a CBOR input source to read from a slice of bytes, backed by a scratch buffer. + pub fn new(slice: &'a [u8], scratch: &'b mut [u8]) -> SliceReadFixed<'a, 'b> { + SliceReadFixed { + slice, + scratch, + index: 0, + scratch_index: 0, + } + } + + fn end(&self, n: usize) -> Result<usize> { + match self.index.checked_add(n) { + Some(end) if end <= self.slice.len() => Ok(end), + _ => Err(Error::syntax( + ErrorCode::EofWhileParsingValue, + self.slice.len() as u64, + )), + } + } + + fn scratch_end(&self, n: usize) -> Result<usize> { + match self.scratch_index.checked_add(n) { + Some(end) if end <= self.scratch.len() => Ok(end), + _ => Err(Error::scratch_too_small(self.index as u64)), + } + } +} + +#[cfg(not(feature = "unsealed_read_write"))] +impl<'a, 'b> private::Sealed for SliceReadFixed<'a, 'b> {} + +impl<'a, 'b> Read<'a> for SliceReadFixed<'a, 'b> { + #[inline] + fn next(&mut self) -> Result<Option<u8>> { + Ok(if self.index < self.slice.len() { + let ch = self.slice[self.index]; + self.index += 1; + Some(ch) + } else { + None + }) + } + + #[inline] + fn peek(&mut self) -> Result<Option<u8>> { + Ok(if self.index < self.slice.len() { + Some(self.slice[self.index]) + } else { + None + }) + } + + fn clear_buffer(&mut self) { + self.scratch_index = 0; + } + + fn read_to_buffer(&mut self, n: usize) -> Result<()> { + let end = self.end(n)?; + let scratch_end = self.scratch_end(n)?; + let slice = &self.slice[self.index..end]; + self.scratch[self.scratch_index..scratch_end].copy_from_slice(&slice); + self.index = end; + self.scratch_index = scratch_end; + + Ok(()) + } + + fn read<'c>(&'c mut self, n: usize) -> Result<EitherLifetime<'c, 'a>> { + let end = self.end(n)?; + let slice = &self.slice[self.index..end]; + self.index = end; + Ok(EitherLifetime::Long(slice)) + } + + fn take_buffer<'c>(&'c mut self) -> EitherLifetime<'c, 'a> { + EitherLifetime::Short(&self.scratch[0..self.scratch_index]) + } + + #[inline] + fn read_into(&mut self, buf: &mut [u8]) -> Result<()> { + let end = self.end(buf.len())?; + buf.copy_from_slice(&self.slice[self.index..end]); + self.index = end; + Ok(()) + } + + #[inline] + fn discard(&mut self) { + self.index += 1; + } + + fn offset(&self) -> u64 { + self.index as u64 + } +} + +#[cfg(any(feature = "std", feature = "alloc"))] +impl<'a, 'b> Offset for SliceReadFixed<'a, 'b> { + #[inline] + fn byte_offset(&self) -> usize { + self.index + } +} + +/// A CBOR input source that reads from a slice of bytes, and can move data around internally to +/// reassemble indefinite strings without the need of an allocated scratch buffer. +#[derive(Debug)] +pub struct MutSliceRead<'a> { + /// A complete view of the reader's data. It is promised that bytes before buffer_end are not + /// mutated any more. + slice: &'a mut [u8], + /// Read cursor position in slice + index: usize, + /// Number of bytes already discarded from the slice + before: usize, + /// End of the buffer area that contains all bytes read_into_buffer. This is always <= index. + buffer_end: usize, +} + +impl<'a> MutSliceRead<'a> { + /// Creates a CBOR input source to read from a slice of bytes. + pub fn new(slice: &'a mut [u8]) -> MutSliceRead<'a> { + MutSliceRead { + slice, + index: 0, + before: 0, + buffer_end: 0, + } + } + + fn end(&self, n: usize) -> Result<usize> { + match self.index.checked_add(n) { + Some(end) if end <= self.slice.len() => Ok(end), + _ => Err(Error::syntax( + ErrorCode::EofWhileParsingValue, + self.slice.len() as u64, + )), + } + } +} + +#[cfg(not(feature = "unsealed_read_write"))] +impl<'a> private::Sealed for MutSliceRead<'a> {} + +impl<'a> Read<'a> for MutSliceRead<'a> { + #[inline] + fn next(&mut self) -> Result<Option<u8>> { + // This is duplicated from SliceRead, can that be eased? + Ok(if self.index < self.slice.len() { + let ch = self.slice[self.index]; + self.index += 1; + Some(ch) + } else { + None + }) + } + + #[inline] + fn peek(&mut self) -> Result<Option<u8>> { + // This is duplicated from SliceRead, can that be eased? + Ok(if self.index < self.slice.len() { + Some(self.slice[self.index]) + } else { + None + }) + } + + fn clear_buffer(&mut self) { + self.slice = &mut mem::replace(&mut self.slice, &mut [])[self.index..]; + self.before += self.index; + self.index = 0; + self.buffer_end = 0; + } + + fn read_to_buffer(&mut self, n: usize) -> Result<()> { + let end = self.end(n)?; + debug_assert!( + self.buffer_end <= self.index, + "MutSliceRead invariant violated: scratch buffer exceeds index" + ); + self.slice[self.buffer_end..end].rotate_left(self.index - self.buffer_end); + self.buffer_end += n; + self.index = end; + + Ok(()) + } + + fn take_buffer<'b>(&'b mut self) -> EitherLifetime<'b, 'a> { + let (left, right) = mem::replace(&mut self.slice, &mut []).split_at_mut(self.index); + self.slice = right; + self.before += self.index; + self.index = 0; + + let left = &left[..self.buffer_end]; + self.buffer_end = 0; + + EitherLifetime::Long(left) + } + + #[inline] + fn read_into(&mut self, buf: &mut [u8]) -> Result<()> { + // This is duplicated from SliceRead, can that be eased? + let end = self.end(buf.len())?; + buf.copy_from_slice(&self.slice[self.index..end]); + self.index = end; + Ok(()) + } + + #[inline] + fn discard(&mut self) { + self.index += 1; + } + + fn offset(&self) -> u64 { + (self.before + self.index) as u64 + } +} |