//! Provides various functions and structs for MessagePack decoding. //! //! Most of the function defined in this module will silently handle interruption error (EINTR) //! received from the given `Read` to be in consistent state with the `Write::write_all` method in //! the standard library. //! //! Any other error would immediately interrupt the parsing process. If your reader can results in //! I/O error and simultaneously be a recoverable state (for example, when reading from //! non-blocking socket and it returns EWOULDBLOCK) be sure that you buffer the data externally //! to avoid data loss (using `BufRead` readers with manual consuming or some other way). mod dec; mod ext; mod sint; mod str; mod uint; #[cfg(feature = "std")] mod est; #[cfg(feature = "std")] pub use est::{MessageLen, LenError}; pub use self::dec::{read_f32, read_f64}; pub use self::ext::{ read_ext_meta, read_fixext1, read_fixext16, read_fixext2, read_fixext4, read_fixext8, ExtMeta, }; pub use self::sint::{read_i16, read_i32, read_i64, read_i8, read_nfix}; #[allow(deprecated)] // While we re-export deprecated items, we don't want to trigger warnings while compiling this crate pub use self::str::{read_str, read_str_from_slice, read_str_len, read_str_ref, DecodeStringError}; pub use self::uint::{read_pfix, read_u16, read_u32, read_u64, read_u8}; use core::fmt::{self, Debug, Display, Formatter}; #[cfg(feature = "std")] use std::error; use num_traits::cast::FromPrimitive; use crate::Marker; pub mod bytes; pub use bytes::Bytes; #[doc(inline)] #[allow(deprecated)] pub use crate::errors::Error; /// The error type for I/O operations on `RmpRead` and associated traits. /// /// For [`std::io::Read`], this is [`std::io::Error`] pub trait RmpReadErr: Display + Debug + crate::errors::MaybeErrBound + 'static {} #[cfg(feature = "std")] impl RmpReadErr for std::io::Error {} impl RmpReadErr for core::convert::Infallible {} macro_rules! read_byteorder_utils { ($($name:ident => $tp:ident),* $(,)?) => { $( #[inline] #[doc(hidden)] fn $name(&mut self) -> Result<$tp, ValueReadError> where Self: Sized { const SIZE: usize = core::mem::size_of::<$tp>(); let mut buf: [u8; SIZE] = [0u8; SIZE]; self.read_exact_buf(&mut buf).map_err(ValueReadError::InvalidDataRead)?; Ok($tp::from_be_bytes(buf)) } )* }; } mod sealed { pub trait Sealed {} #[cfg(feature = "std")] impl Sealed for T {} #[cfg(not(feature = "std"))] impl<'a> Sealed for &'a [u8] {} impl Sealed for super::Bytes<'_> {} } /// A type that `rmp` supports reading from. /// /// The methods of this trait should be considered an implementation detail (for now). /// It is currently sealed (can not be implemented by the user). /// /// Its primary implementations are [`std::io::Read`] and [Bytes]. pub trait RmpRead: sealed::Sealed { type Error: RmpReadErr; /// Read a single (unsigned) byte from this stream #[inline] fn read_u8(&mut self) -> Result { let mut buf = [0; 1]; self.read_exact_buf(&mut buf)?; Ok(buf[0]) } /// Read the exact number of bytes needed to fill the specified buffer. /// /// If there are not enough bytes, this will return an error. /// /// See also [`std::io::Read::read_exact`] fn read_exact_buf(&mut self, buf: &mut [u8]) -> Result<(), Self::Error>; // Internal helper functions to map I/O error into the `InvalidDataRead` error. /// Read a single (unsigned) byte from this stream. #[inline] #[doc(hidden)] fn read_data_u8(&mut self) -> Result> { self.read_u8().map_err(ValueReadError::InvalidDataRead) } /// Read a single (signed) byte from this stream. #[inline] #[doc(hidden)] fn read_data_i8(&mut self) -> Result> { self.read_data_u8().map(|b| b as i8) } read_byteorder_utils!( read_data_u16 => u16, read_data_u32 => u32, read_data_u64 => u64, read_data_i16 => i16, read_data_i32 => i32, read_data_i64 => i64, read_data_f32 => f32, read_data_f64 => f64 ); } #[cfg(feature = "std")] impl RmpRead for T { type Error = std::io::Error; #[inline] fn read_exact_buf(&mut self, buf: &mut [u8]) -> Result<(), Self::Error> { std::io::Read::read_exact(self, buf) } } /// An error that can occur when attempting to read a MessagePack marker from the reader. #[derive(Debug)] #[allow(deprecated)] // Needed for backwards compat pub struct MarkerReadError(pub E); /// An error which can occur when attempting to read a MessagePack value from the reader. #[derive(Debug)] #[allow(deprecated)] // Needed for backwards compat pub enum ValueReadError { /// Failed to read the marker. InvalidMarkerRead(E), /// Failed to read the data. InvalidDataRead(E), /// The type decoded isn't match with the expected one. TypeMismatch(Marker), } #[cfg(feature = "std")] impl error::Error for ValueReadError { #[cold] fn source(&self) -> Option<&(dyn error::Error + 'static)> { match *self { Self::InvalidMarkerRead(ref err) | Self::InvalidDataRead(ref err) => Some(err), Self::TypeMismatch(..) => None, } } } impl Display for ValueReadError { #[cold] fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), fmt::Error> { // TODO: This should probably use formatting f.write_str(match *self { Self::InvalidMarkerRead(..) => "failed to read MessagePack marker", Self::InvalidDataRead(..) => "failed to read MessagePack data", Self::TypeMismatch(..) => "the type decoded isn't match with the expected one", }) } } impl From> for ValueReadError { #[cold] fn from(err: MarkerReadError) -> Self { match err { MarkerReadError(err) => Self::InvalidMarkerRead(err), } } } impl From for MarkerReadError { #[cold] fn from(err: E) -> Self { Self(err) } } /// Attempts to read a single byte from the given reader and to decode it as a MessagePack marker. #[inline] pub fn read_marker(rd: &mut R) -> Result> { Ok(Marker::from_u8(rd.read_u8()?)) } /// Attempts to read a single byte from the given reader and to decode it as a nil value. /// /// According to the MessagePack specification, a nil value is represented as a single `0xc0` byte. /// /// # Errors /// /// This function will return `ValueReadError` on any I/O error while reading the nil marker, /// except the EINTR, which is handled internally. /// /// It also returns `ValueReadError::TypeMismatch` if the actual type is not equal with the /// expected one, indicating you with the actual type. /// /// # Note /// /// This function will silently retry on every EINTR received from the underlying `Read` until /// successful read. pub fn read_nil(rd: &mut R) -> Result<(), ValueReadError> { match read_marker(rd)? { Marker::Null => Ok(()), marker => Err(ValueReadError::TypeMismatch(marker)), } } /// Attempts to read a single byte from the given reader and to decode it as a boolean value. /// /// According to the MessagePack specification, an encoded boolean value is represented as a single /// byte. /// /// # Errors /// /// This function will return `ValueReadError` on any I/O error while reading the bool marker, /// except the EINTR, which is handled internally. /// /// It also returns `ValueReadError::TypeMismatch` if the actual type is not equal with the /// expected one, indicating you with the actual type. /// /// # Note /// /// This function will silently retry on every EINTR received from the underlying `Read` until /// successful read. pub fn read_bool(rd: &mut R) -> Result> { match read_marker(rd)? { Marker::True => Ok(true), Marker::False => Ok(false), marker => Err(ValueReadError::TypeMismatch(marker)), } } /// An error which can occur when attempting to read a MessagePack numeric value from the reader. #[derive(Debug)] #[allow(deprecated)] // Used for compatibility pub enum NumValueReadError { /// Failed to read the marker. InvalidMarkerRead(E), /// Failed to read the data. InvalidDataRead(E), /// The type decoded isn't match with the expected one. TypeMismatch(Marker), /// Out of range integral type conversion attempted. OutOfRange, } #[cfg(feature = "std")] impl error::Error for NumValueReadError { fn source(&self) -> Option<&(dyn error::Error + 'static)> { match *self { Self::InvalidMarkerRead(ref err) | Self::InvalidDataRead(ref err) => Some(err), Self::TypeMismatch(..) | Self::OutOfRange => None, } } } impl Display for NumValueReadError { fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), fmt::Error> { f.write_str(match *self { Self::InvalidMarkerRead(..) => "failed to read MessagePack marker", Self::InvalidDataRead(..) => "failed to read MessagePack data", Self::TypeMismatch(..) => "the type decoded isn't match with the expected one", Self::OutOfRange => "out of range integral type conversion attempted", }) } } impl From> for NumValueReadError { #[cold] fn from(err: MarkerReadError) -> Self { match err { MarkerReadError(err) => Self::InvalidMarkerRead(err), } } } impl From> for NumValueReadError { #[cold] fn from(err: ValueReadError) -> Self { match err { ValueReadError::InvalidMarkerRead(err) => Self::InvalidMarkerRead(err), ValueReadError::InvalidDataRead(err) => Self::InvalidDataRead(err), ValueReadError::TypeMismatch(err) => Self::TypeMismatch(err), } } } /// Attempts to read up to 9 bytes from the given reader and to decode them as integral `T` value. /// /// This function will try to read up to 9 bytes from the reader (1 for marker and up to 8 for data) /// and interpret them as a big-endian `T`. /// /// Unlike `read_*`, this function weakens type restrictions, allowing you to safely decode packed /// values even if you aren't sure about the actual integral type. /// /// # Errors /// /// This function will return `NumValueReadError` on any I/O error while reading either the marker /// or the data. /// /// It also returns `NumValueReadError::OutOfRange` if the actual type is not an integer or it does /// not fit in the given numeric range. /// /// # Examples /// /// ``` /// let buf = [0xcd, 0x1, 0x2c]; /// /// assert_eq!(300u16, rmp::decode::read_int(&mut &buf[..]).unwrap()); /// assert_eq!(300i16, rmp::decode::read_int(&mut &buf[..]).unwrap()); /// assert_eq!(300u32, rmp::decode::read_int(&mut &buf[..]).unwrap()); /// assert_eq!(300i32, rmp::decode::read_int(&mut &buf[..]).unwrap()); /// assert_eq!(300u64, rmp::decode::read_int(&mut &buf[..]).unwrap()); /// assert_eq!(300i64, rmp::decode::read_int(&mut &buf[..]).unwrap()); /// assert_eq!(300usize, rmp::decode::read_int(&mut &buf[..]).unwrap()); /// assert_eq!(300isize, rmp::decode::read_int(&mut &buf[..]).unwrap()); /// ``` pub fn read_int(rd: &mut R) -> Result> { let val = match read_marker(rd)? { Marker::FixPos(val) => T::from_u8(val), Marker::FixNeg(val) => T::from_i8(val), Marker::U8 => T::from_u8(rd.read_data_u8()?), Marker::U16 => T::from_u16(rd.read_data_u16()?), Marker::U32 => T::from_u32(rd.read_data_u32()?), Marker::U64 => T::from_u64(rd.read_data_u64()?), Marker::I8 => T::from_i8(rd.read_data_i8()?), Marker::I16 => T::from_i16(rd.read_data_i16()?), Marker::I32 => T::from_i32(rd.read_data_i32()?), Marker::I64 => T::from_i64(rd.read_data_i64()?), marker => return Err(NumValueReadError::TypeMismatch(marker)), }; val.ok_or(NumValueReadError::OutOfRange) } /// Attempts to read up to 5 bytes from the given reader and to decode them as a big-endian u32 /// array size. /// /// Array format family stores a sequence of elements in 1, 3, or 5 bytes of extra bytes in addition /// to the elements. /// /// # Note /// /// This function will silently retry on every EINTR received from the underlying `Read` until /// successful read. // TODO: Docs. // NOTE: EINTR is managed internally. pub fn read_array_len(rd: &mut R) -> Result> where R: RmpRead, { match read_marker(rd)? { Marker::FixArray(size) => Ok(u32::from(size)), Marker::Array16 => Ok(u32::from(rd.read_data_u16()?)), Marker::Array32 => Ok(rd.read_data_u32()?), marker => Err(ValueReadError::TypeMismatch(marker)), } } /// Attempts to read up to 5 bytes from the given reader and to decode them as a big-endian u32 /// map size. /// /// Map format family stores a sequence of elements in 1, 3, or 5 bytes of extra bytes in addition /// to the elements. /// /// # Note /// /// This function will silently retry on every EINTR received from the underlying `Read` until /// successful read. // TODO: Docs. pub fn read_map_len(rd: &mut R) -> Result> { let marker = read_marker(rd)?; marker_to_len(rd, marker) } pub fn marker_to_len(rd: &mut R, marker: Marker) -> Result> { match marker { Marker::FixMap(size) => Ok(u32::from(size)), Marker::Map16 => Ok(u32::from(rd.read_data_u16()?)), Marker::Map32 => Ok(rd.read_data_u32()?), marker => Err(ValueReadError::TypeMismatch(marker)), } } /// Attempts to read up to 5 bytes from the given reader and to decode them as Binary array length. /// /// # Note /// /// This function will silently retry on every EINTR received from the underlying `Read` until /// successful read. // TODO: Docs. pub fn read_bin_len(rd: &mut R) -> Result> { match read_marker(rd)? { Marker::Bin8 => Ok(u32::from(rd.read_data_u8()?)), Marker::Bin16 => Ok(u32::from(rd.read_data_u16()?)), Marker::Bin32 => Ok(rd.read_data_u32()?), marker => Err(ValueReadError::TypeMismatch(marker)), } }