diff --git a/src/config.rs b/src/config.rs index 8d2fc93..f575ee7 100644 --- a/src/config.rs +++ b/src/config.rs @@ -12,7 +12,10 @@ //! .with_little_endian() //! // pick one of: //! .with_variable_int_encoding() -//! .with_fixed_int_encoding(); +//! .with_fixed_int_encoding() +//! // pick one of: +//! .skip_fixed_array_length() +//! .write_fixed_array_length(); //! ``` //! //! See [Config] for more information on the configuration options. @@ -26,12 +29,15 @@ use core::marker::PhantomData; /// /// - [with_little_endian] and [with_big_endian] /// - [with_fixed_int_encoding] and [with_variable_int_encoding] +/// - [skip_fixed_array_length] and [write_fixed_array_length] /// /// /// [with_little_endian]: #method.with_little_endian /// [with_big_endian]: #method.with_big_endian /// [with_fixed_int_encoding]: #method.with_fixed_int_encoding /// [with_variable_int_encoding]: #method.with_variable_int_encoding +/// [skip_fixed_array_length]: #method.skip_fixed_array_length +/// [write_fixed_array_length]: #method.write_fixed_array_length pub trait Config: InternalConfig { /// Makes bincode encode all integer types in big endian. fn with_big_endian(self) -> BigEndian { @@ -97,6 +103,16 @@ pub trait Config: InternalConfig { fn with_fixed_int_encoding(self) -> Fixint { Fixint { _pd: PhantomData } } + + /// Skip writing the length of fixed size arrays (`[u8; N]`) before writing the array + fn skip_fixed_array_length(self) -> SkipFixedArrayLength { + SkipFixedArrayLength { _pd: PhantomData } + } + + /// Write the length of fixed size arrays (`[u8; N]`) before writing the array + fn write_fixed_array_length(self) -> WriteFixedArrayLength { + WriteFixedArrayLength { _pd: PhantomData } + } } impl Config for T {} @@ -104,6 +120,7 @@ impl Config for T {} /// The default config. By default this will be: /// - Little endian /// - Variable int encoding +/// - Skip fixed array length #[derive(Copy, Clone)] pub struct Default; @@ -112,6 +129,7 @@ impl InternalConfig for Default { const INT_ENCODING: IntEncoding = IntEncoding::Variable; const LIMIT: Option = None; const ALLOW_TRAILING: bool = true; + const SKIP_FIXED_ARRAY_LENGTH: bool = true; } #[doc(hidden)] @@ -125,6 +143,7 @@ impl InternalConfig for BigEndian { const INT_ENCODING: IntEncoding = C::INT_ENCODING; const LIMIT: Option = C::LIMIT; const ALLOW_TRAILING: bool = C::ALLOW_TRAILING; + const SKIP_FIXED_ARRAY_LENGTH: bool = C::SKIP_FIXED_ARRAY_LENGTH; } #[doc(hidden)] @@ -138,6 +157,7 @@ impl InternalConfig for LittleEndian { const INT_ENCODING: IntEncoding = C::INT_ENCODING; const LIMIT: Option = C::LIMIT; const ALLOW_TRAILING: bool = C::ALLOW_TRAILING; + const SKIP_FIXED_ARRAY_LENGTH: bool = C::SKIP_FIXED_ARRAY_LENGTH; } #[doc(hidden)] @@ -151,6 +171,7 @@ impl InternalConfig for Fixint { const INT_ENCODING: IntEncoding = IntEncoding::Fixed; const LIMIT: Option = C::LIMIT; const ALLOW_TRAILING: bool = C::ALLOW_TRAILING; + const SKIP_FIXED_ARRAY_LENGTH: bool = C::SKIP_FIXED_ARRAY_LENGTH; } #[doc(hidden)] @@ -164,6 +185,35 @@ impl InternalConfig for Varint { const INT_ENCODING: IntEncoding = IntEncoding::Variable; const LIMIT: Option = C::LIMIT; const ALLOW_TRAILING: bool = C::ALLOW_TRAILING; + const SKIP_FIXED_ARRAY_LENGTH: bool = C::SKIP_FIXED_ARRAY_LENGTH; +} + +#[doc(hidden)] +#[derive(Copy, Clone)] +pub struct SkipFixedArrayLength { + _pd: PhantomData, +} + +impl InternalConfig for SkipFixedArrayLength { + const ENDIAN: Endian = C::ENDIAN; + const INT_ENCODING: IntEncoding = C::INT_ENCODING; + const LIMIT: Option = C::LIMIT; + const ALLOW_TRAILING: bool = C::ALLOW_TRAILING; + const SKIP_FIXED_ARRAY_LENGTH: bool = true; +} + +#[doc(hidden)] +#[derive(Copy, Clone)] +pub struct WriteFixedArrayLength { + _pd: PhantomData, +} + +impl InternalConfig for WriteFixedArrayLength { + const ENDIAN: Endian = C::ENDIAN; + const INT_ENCODING: IntEncoding = C::INT_ENCODING; + const LIMIT: Option = C::LIMIT; + const ALLOW_TRAILING: bool = C::ALLOW_TRAILING; + const SKIP_FIXED_ARRAY_LENGTH: bool = false; } mod internal { @@ -172,6 +222,7 @@ mod internal { const INT_ENCODING: IntEncoding; const LIMIT: Option; const ALLOW_TRAILING: bool; + const SKIP_FIXED_ARRAY_LENGTH: bool; } #[derive(PartialEq, Eq)] @@ -194,5 +245,6 @@ mod internal { const INT_ENCODING: IntEncoding = C::INT_ENCODING; const LIMIT: Option = C::LIMIT; const ALLOW_TRAILING: bool = C::ALLOW_TRAILING; + const SKIP_FIXED_ARRAY_LENGTH: bool = C::SKIP_FIXED_ARRAY_LENGTH; } } diff --git a/src/de/decoder.rs b/src/de/decoder.rs index cff80d1..8b29cfb 100644 --- a/src/de/decoder.rs +++ b/src/de/decoder.rs @@ -1,281 +1,290 @@ -use super::{ - read::{BorrowReader, Reader}, - BorrowDecode, Decode, -}; -use crate::{ - config::{Config, Endian, IntEncoding}, - error::DecodeError, -}; -use core::marker::PhantomData; - -/// A Decoder that reads bytes from a given reader `R`. -/// -/// This struct should rarely be used. -/// In most cases, prefer any of the `decode` functions. -/// -/// The ByteOrder that is chosen will impact the endianness that -/// is used to read integers out of the reader. -/// -/// ``` -/// # let slice: &[u8] = &[0, 0, 0, 0]; -/// # let some_reader = bincode::de::read::SliceReader::new(slice); -/// use bincode::de::{Decoder, Decodable}; -/// use bincode::config; -/// let mut decoder = Decoder::new(some_reader, config::Default); -/// // this u32 can be any Decodable -/// let value = u32::decode(&mut decoder).unwrap(); -/// ``` -pub struct Decoder { - reader: R, - config: PhantomData, -} - -impl<'de, R: Reader<'de>, C: Config> Decoder { - /// Construct a new Decoder - pub fn new(reader: R, _config: C) -> Decoder { - Decoder { - reader, - config: PhantomData, - } - } - - /// Consume the decoder and return the inner reader - pub fn into_reader(self) -> R { - self.reader - } -} - -impl<'a, 'de, R: BorrowReader<'de>, C: Config> BorrowDecode<'de> for &'a mut Decoder { - fn decode_slice(&mut self, len: usize) -> Result<&'de [u8], DecodeError> { - self.reader.take_bytes(len) - } -} - -impl<'a, 'de, R: Reader<'de>, C: Config> Decode for &'a mut Decoder { - fn decode_u8(&mut self) -> Result { - let mut bytes = [0u8; 1]; - self.reader.read(&mut bytes)?; - Ok(bytes[0]) - } - - fn decode_u16(&mut self) -> Result { - match C::INT_ENCODING { - IntEncoding::Variable => crate::varint::varint_decode_u16(&mut self.reader, C::ENDIAN), - IntEncoding::Fixed => { - let mut bytes = [0u8; 2]; - self.reader.read(&mut bytes)?; - Ok(match C::ENDIAN { - Endian::Little => u16::from_le_bytes(bytes), - Endian::Big => u16::from_be_bytes(bytes), - }) - } - } - } - - fn decode_u32(&mut self) -> Result { - match C::INT_ENCODING { - IntEncoding::Variable => crate::varint::varint_decode_u32(&mut self.reader, C::ENDIAN), - IntEncoding::Fixed => { - let mut bytes = [0u8; 4]; - self.reader.read(&mut bytes)?; - Ok(match C::ENDIAN { - Endian::Little => u32::from_le_bytes(bytes), - Endian::Big => u32::from_be_bytes(bytes), - }) - } - } - } - - fn decode_u64(&mut self) -> Result { - match C::INT_ENCODING { - IntEncoding::Variable => crate::varint::varint_decode_u64(&mut self.reader, C::ENDIAN), - IntEncoding::Fixed => { - let mut bytes = [0u8; 8]; - self.reader.read(&mut bytes)?; - Ok(match C::ENDIAN { - Endian::Little => u64::from_le_bytes(bytes), - Endian::Big => u64::from_be_bytes(bytes), - }) - } - } - } - - fn decode_u128(&mut self) -> Result { - match C::INT_ENCODING { - IntEncoding::Variable => crate::varint::varint_decode_u128(&mut self.reader, C::ENDIAN), - IntEncoding::Fixed => { - let mut bytes = [0u8; 16]; - self.reader.read(&mut bytes)?; - Ok(match C::ENDIAN { - Endian::Little => u128::from_le_bytes(bytes), - Endian::Big => u128::from_be_bytes(bytes), - }) - } - } - } - - fn decode_usize(&mut self) -> Result { - match C::INT_ENCODING { - IntEncoding::Variable => { - crate::varint::varint_decode_usize(&mut self.reader, C::ENDIAN) - } - IntEncoding::Fixed => { - let mut bytes = [0u8; 8]; - self.reader.read(&mut bytes)?; - Ok(match C::ENDIAN { - Endian::Little => u64::from_le_bytes(bytes), - Endian::Big => u64::from_be_bytes(bytes), - } as usize) - } - } - } - - fn decode_i8(&mut self) -> Result { - let mut bytes = [0u8; 1]; - self.reader.read(&mut bytes)?; - Ok(bytes[0] as i8) - } - - fn decode_i16(&mut self) -> Result { - match C::INT_ENCODING { - IntEncoding::Variable => crate::varint::varint_decode_i16(&mut self.reader, C::ENDIAN), - IntEncoding::Fixed => { - let mut bytes = [0u8; 2]; - self.reader.read(&mut bytes)?; - Ok(match C::ENDIAN { - Endian::Little => i16::from_le_bytes(bytes), - Endian::Big => i16::from_be_bytes(bytes), - }) - } - } - } - - fn decode_i32(&mut self) -> Result { - match C::INT_ENCODING { - IntEncoding::Variable => crate::varint::varint_decode_i32(&mut self.reader, C::ENDIAN), - IntEncoding::Fixed => { - let mut bytes = [0u8; 4]; - self.reader.read(&mut bytes)?; - Ok(match C::ENDIAN { - Endian::Little => i32::from_le_bytes(bytes), - Endian::Big => i32::from_be_bytes(bytes), - }) - } - } - } - - fn decode_i64(&mut self) -> Result { - match C::INT_ENCODING { - IntEncoding::Variable => crate::varint::varint_decode_i64(&mut self.reader, C::ENDIAN), - IntEncoding::Fixed => { - let mut bytes = [0u8; 8]; - self.reader.read(&mut bytes)?; - Ok(match C::ENDIAN { - Endian::Little => i64::from_le_bytes(bytes), - Endian::Big => i64::from_be_bytes(bytes), - }) - } - } - } - - fn decode_i128(&mut self) -> Result { - match C::INT_ENCODING { - IntEncoding::Variable => crate::varint::varint_decode_i128(&mut self.reader, C::ENDIAN), - IntEncoding::Fixed => { - let mut bytes = [0u8; 16]; - self.reader.read(&mut bytes)?; - Ok(match C::ENDIAN { - Endian::Little => i128::from_le_bytes(bytes), - Endian::Big => i128::from_be_bytes(bytes), - }) - } - } - } - - fn decode_isize(&mut self) -> Result { - match C::INT_ENCODING { - IntEncoding::Variable => { - crate::varint::varint_decode_isize(&mut self.reader, C::ENDIAN) - } - IntEncoding::Fixed => { - let mut bytes = [0u8; 8]; - self.reader.read(&mut bytes)?; - Ok(match C::ENDIAN { - Endian::Little => i64::from_le_bytes(bytes), - Endian::Big => i64::from_be_bytes(bytes), - } as isize) - } - } - } - - fn decode_f32(&mut self) -> Result { - let mut bytes = [0u8; 4]; - self.reader.read(&mut bytes)?; - Ok(match C::ENDIAN { - Endian::Little => f32::from_le_bytes(bytes), - Endian::Big => f32::from_be_bytes(bytes), - }) - } - - fn decode_f64(&mut self) -> Result { - let mut bytes = [0u8; 8]; - self.reader.read(&mut bytes)?; - Ok(match C::ENDIAN { - Endian::Little => f64::from_le_bytes(bytes), - Endian::Big => f64::from_be_bytes(bytes), - }) - } - - fn decode_array(&mut self) -> Result<[u8; N], DecodeError> { - let mut array = [0u8; N]; - self.reader.read(&mut array)?; - Ok(array) - } - - fn decode_char(&mut self) -> Result { - let mut array = [0u8; 4]; - - // Look at the first byte to see how many bytes must be read - self.reader.read(&mut array[..1])?; - - let width = utf8_char_width(array[0]); - if width == 0 { - return Err(DecodeError::InvalidCharEncoding(array)); - } - if width == 1 { - return Ok(array[0] as char); - } - - // read the remaining pain - self.reader.read(&mut array[1..width])?; - let res = core::str::from_utf8(&array[..width]) - .ok() - .and_then(|s| s.chars().next()) - .ok_or(DecodeError::InvalidCharEncoding(array))?; - Ok(res) - } -} - -const UTF8_CHAR_WIDTH: [u8; 256] = [ - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, // 0x1F - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, // 0x3F - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, // 0x5F - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, // 0x7F - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, // 0x9F - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, // 0xBF - 0, 0, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, // 0xDF - 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, // 0xEF - 4, 4, 4, 4, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 0xFF -]; - -// This function is a copy of core::str::utf8_char_width -const fn utf8_char_width(b: u8) -> usize { - UTF8_CHAR_WIDTH[b as usize] as usize -} +use super::{ + read::{BorrowReader, Reader}, + BorrowDecode, Decode, +}; +use crate::{ + config::{Config, Endian, IntEncoding}, + error::DecodeError, +}; +use core::marker::PhantomData; + +/// A Decoder that reads bytes from a given reader `R`. +/// +/// This struct should rarely be used. +/// In most cases, prefer any of the `decode` functions. +/// +/// The ByteOrder that is chosen will impact the endianness that +/// is used to read integers out of the reader. +/// +/// ``` +/// # let slice: &[u8] = &[0, 0, 0, 0]; +/// # let some_reader = bincode::de::read::SliceReader::new(slice); +/// use bincode::de::{Decoder, Decodable}; +/// use bincode::config; +/// let mut decoder = Decoder::new(some_reader, config::Default); +/// // this u32 can be any Decodable +/// let value = u32::decode(&mut decoder).unwrap(); +/// ``` +pub struct Decoder { + reader: R, + config: PhantomData, +} + +impl<'de, R: Reader<'de>, C: Config> Decoder { + /// Construct a new Decoder + pub fn new(reader: R, _config: C) -> Decoder { + Decoder { + reader, + config: PhantomData, + } + } + + /// Consume the decoder and return the inner reader + pub fn into_reader(self) -> R { + self.reader + } +} + +impl<'a, 'de, R: BorrowReader<'de>, C: Config> BorrowDecode<'de> for &'a mut Decoder { + fn decode_slice(&mut self, len: usize) -> Result<&'de [u8], DecodeError> { + self.reader.take_bytes(len) + } +} + +impl<'a, 'de, R: Reader<'de>, C: Config> Decode for &'a mut Decoder { + fn decode_u8(&mut self) -> Result { + let mut bytes = [0u8; 1]; + self.reader.read(&mut bytes)?; + Ok(bytes[0]) + } + + fn decode_u16(&mut self) -> Result { + match C::INT_ENCODING { + IntEncoding::Variable => crate::varint::varint_decode_u16(&mut self.reader, C::ENDIAN), + IntEncoding::Fixed => { + let mut bytes = [0u8; 2]; + self.reader.read(&mut bytes)?; + Ok(match C::ENDIAN { + Endian::Little => u16::from_le_bytes(bytes), + Endian::Big => u16::from_be_bytes(bytes), + }) + } + } + } + + fn decode_u32(&mut self) -> Result { + match C::INT_ENCODING { + IntEncoding::Variable => crate::varint::varint_decode_u32(&mut self.reader, C::ENDIAN), + IntEncoding::Fixed => { + let mut bytes = [0u8; 4]; + self.reader.read(&mut bytes)?; + Ok(match C::ENDIAN { + Endian::Little => u32::from_le_bytes(bytes), + Endian::Big => u32::from_be_bytes(bytes), + }) + } + } + } + + fn decode_u64(&mut self) -> Result { + match C::INT_ENCODING { + IntEncoding::Variable => crate::varint::varint_decode_u64(&mut self.reader, C::ENDIAN), + IntEncoding::Fixed => { + let mut bytes = [0u8; 8]; + self.reader.read(&mut bytes)?; + Ok(match C::ENDIAN { + Endian::Little => u64::from_le_bytes(bytes), + Endian::Big => u64::from_be_bytes(bytes), + }) + } + } + } + + fn decode_u128(&mut self) -> Result { + match C::INT_ENCODING { + IntEncoding::Variable => crate::varint::varint_decode_u128(&mut self.reader, C::ENDIAN), + IntEncoding::Fixed => { + let mut bytes = [0u8; 16]; + self.reader.read(&mut bytes)?; + Ok(match C::ENDIAN { + Endian::Little => u128::from_le_bytes(bytes), + Endian::Big => u128::from_be_bytes(bytes), + }) + } + } + } + + fn decode_usize(&mut self) -> Result { + match C::INT_ENCODING { + IntEncoding::Variable => { + crate::varint::varint_decode_usize(&mut self.reader, C::ENDIAN) + } + IntEncoding::Fixed => { + let mut bytes = [0u8; 8]; + self.reader.read(&mut bytes)?; + Ok(match C::ENDIAN { + Endian::Little => u64::from_le_bytes(bytes), + Endian::Big => u64::from_be_bytes(bytes), + } as usize) + } + } + } + + fn decode_i8(&mut self) -> Result { + let mut bytes = [0u8; 1]; + self.reader.read(&mut bytes)?; + Ok(bytes[0] as i8) + } + + fn decode_i16(&mut self) -> Result { + match C::INT_ENCODING { + IntEncoding::Variable => crate::varint::varint_decode_i16(&mut self.reader, C::ENDIAN), + IntEncoding::Fixed => { + let mut bytes = [0u8; 2]; + self.reader.read(&mut bytes)?; + Ok(match C::ENDIAN { + Endian::Little => i16::from_le_bytes(bytes), + Endian::Big => i16::from_be_bytes(bytes), + }) + } + } + } + + fn decode_i32(&mut self) -> Result { + match C::INT_ENCODING { + IntEncoding::Variable => crate::varint::varint_decode_i32(&mut self.reader, C::ENDIAN), + IntEncoding::Fixed => { + let mut bytes = [0u8; 4]; + self.reader.read(&mut bytes)?; + Ok(match C::ENDIAN { + Endian::Little => i32::from_le_bytes(bytes), + Endian::Big => i32::from_be_bytes(bytes), + }) + } + } + } + + fn decode_i64(&mut self) -> Result { + match C::INT_ENCODING { + IntEncoding::Variable => crate::varint::varint_decode_i64(&mut self.reader, C::ENDIAN), + IntEncoding::Fixed => { + let mut bytes = [0u8; 8]; + self.reader.read(&mut bytes)?; + Ok(match C::ENDIAN { + Endian::Little => i64::from_le_bytes(bytes), + Endian::Big => i64::from_be_bytes(bytes), + }) + } + } + } + + fn decode_i128(&mut self) -> Result { + match C::INT_ENCODING { + IntEncoding::Variable => crate::varint::varint_decode_i128(&mut self.reader, C::ENDIAN), + IntEncoding::Fixed => { + let mut bytes = [0u8; 16]; + self.reader.read(&mut bytes)?; + Ok(match C::ENDIAN { + Endian::Little => i128::from_le_bytes(bytes), + Endian::Big => i128::from_be_bytes(bytes), + }) + } + } + } + + fn decode_isize(&mut self) -> Result { + match C::INT_ENCODING { + IntEncoding::Variable => { + crate::varint::varint_decode_isize(&mut self.reader, C::ENDIAN) + } + IntEncoding::Fixed => { + let mut bytes = [0u8; 8]; + self.reader.read(&mut bytes)?; + Ok(match C::ENDIAN { + Endian::Little => i64::from_le_bytes(bytes), + Endian::Big => i64::from_be_bytes(bytes), + } as isize) + } + } + } + + fn decode_f32(&mut self) -> Result { + let mut bytes = [0u8; 4]; + self.reader.read(&mut bytes)?; + Ok(match C::ENDIAN { + Endian::Little => f32::from_le_bytes(bytes), + Endian::Big => f32::from_be_bytes(bytes), + }) + } + + fn decode_f64(&mut self) -> Result { + let mut bytes = [0u8; 8]; + self.reader.read(&mut bytes)?; + Ok(match C::ENDIAN { + Endian::Little => f64::from_le_bytes(bytes), + Endian::Big => f64::from_be_bytes(bytes), + }) + } + + fn decode_array(&mut self) -> Result<[u8; N], DecodeError> { + let mut array = [0u8; N]; + if !C::SKIP_FIXED_ARRAY_LENGTH { + let length = self.decode_usize()?; + if length != N { + return Err(DecodeError::ArrayLengthMismatch { + found: length, + required: N, + }); + } + } + self.reader.read(&mut array)?; + Ok(array) + } + + fn decode_char(&mut self) -> Result { + let mut array = [0u8; 4]; + + // Look at the first byte to see how many bytes must be read + self.reader.read(&mut array[..1])?; + + let width = utf8_char_width(array[0]); + if width == 0 { + return Err(DecodeError::InvalidCharEncoding(array)); + } + if width == 1 { + return Ok(array[0] as char); + } + + // read the remaining pain + self.reader.read(&mut array[1..width])?; + let res = core::str::from_utf8(&array[..width]) + .ok() + .and_then(|s| s.chars().next()) + .ok_or(DecodeError::InvalidCharEncoding(array))?; + Ok(res) + } +} + +const UTF8_CHAR_WIDTH: [u8; 256] = [ + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, // 0x1F + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, // 0x3F + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, // 0x5F + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, // 0x7F + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, // 0x9F + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, // 0xBF + 0, 0, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, // 0xDF + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, // 0xEF + 4, 4, 4, 4, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 0xFF +]; + +// This function is a copy of core::str::utf8_char_width +const fn utf8_char_width(b: u8) -> usize { + UTF8_CHAR_WIDTH[b as usize] as usize +} diff --git a/src/enc/encoder.rs b/src/enc/encoder.rs index 09ac901..a942b2d 100644 --- a/src/enc/encoder.rs +++ b/src/enc/encoder.rs @@ -195,6 +195,9 @@ impl<'a, W: Writer, C: Config> Encode for &'a mut Encoder { } fn encode_array(&mut self, val: [u8; N]) -> Result<(), EncodeError> { + if !C::SKIP_FIXED_ARRAY_LENGTH { + self.encode_usize(N)?; + } self.writer.write(&val) } diff --git a/src/error.rs b/src/error.rs index 86c36ee..eb0c66c 100644 --- a/src/error.rs +++ b/src/error.rs @@ -52,6 +52,14 @@ pub enum DecodeError { /// The decoder tried to decode a `bool` and failed. The given value is what is actually read. InvalidBooleanValue(u8), + + /// The decoder tried to decode an array of length `required`, but the binary data contained an array of length `found`. + ArrayLengthMismatch { + /// The length of the array required by the rust type. + required: usize, + /// The length of the array found in the binary format. + found: usize, + }, } /// Integer types. Used by [DecodeError]. These types have no purpose other than being shown in errors. diff --git a/tests/basic_types.rs b/tests/basic_types.rs index d7a48a4..d5cc68d 100644 --- a/tests/basic_types.rs +++ b/tests/basic_types.rs @@ -11,7 +11,7 @@ where + 'static, C: Config, { - let mut buffer = [0u8; 32]; + let mut buffer = [0u8; 1024]; let len = bincode::encode_into_slice_with_config(element.clone(), &mut buffer, config).unwrap(); println!( "{:?}: {:?} ({:?})", @@ -32,27 +32,62 @@ where + Clone + 'static, { + // A matrix of each different config option possible the_same_with_config( element.clone(), config::Default .with_little_endian() - .with_fixed_int_encoding(), + .with_fixed_int_encoding() + .skip_fixed_array_length(), ); the_same_with_config( element.clone(), - config::Default.with_big_endian().with_fixed_int_encoding(), + config::Default + .with_big_endian() + .with_fixed_int_encoding() + .skip_fixed_array_length(), ); the_same_with_config( element.clone(), config::Default .with_little_endian() - .with_variable_int_encoding(), + .with_variable_int_encoding() + .skip_fixed_array_length(), + ); + the_same_with_config( + element.clone(), + config::Default + .with_big_endian() + .with_variable_int_encoding() + .skip_fixed_array_length(), + ); + the_same_with_config( + element.clone(), + config::Default + .with_little_endian() + .with_fixed_int_encoding() + .write_fixed_array_length(), + ); + the_same_with_config( + element.clone(), + config::Default + .with_big_endian() + .with_fixed_int_encoding() + .write_fixed_array_length(), + ); + the_same_with_config( + element.clone(), + config::Default + .with_little_endian() + .with_variable_int_encoding() + .write_fixed_array_length(), ); the_same_with_config( element, config::Default .with_big_endian() - .with_variable_int_encoding(), + .with_variable_int_encoding() + .write_fixed_array_length(), ); } @@ -95,6 +130,27 @@ fn test_numbers() { the_same((1u8, 2u8, 3u8, 4u8, 5u8, 6u8)); the_same((1u8, 2u8, 3u8, 4u8, 5u8, 6u8, 7u8)); the_same((1u8, 2u8, 3u8, 4u8, 5u8, 6u8, 7u8, 8u8)); + + // arrays + #[rustfmt::skip] + the_same([ + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, + 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, + 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, + 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, + 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, + 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, + 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, + 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, + 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, + 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, + 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, 176, + 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, + 193, 194, 195, 196, 197, 198, 199, 200, 201, 202, 203, 204, 205, 206, 207, 208, + 209, 210, 211, 212, 213, 214, 215, 216, 217, 218, 219, 220, 221, 222, 223, 224, + 225, 226, 227, 228, 229, 230, 231, 232, 233, 234, 235, 236, 237, 238, 239, 240, + 241, 242, 243, 244, 245, 246, 247, 248, 249, 250, 251, 252, 253, 254, 255 + ]); } #[test]