Revision control
Copy as Markdown
Other Tools
#[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
}
}