diff --git a/src/config.rs b/src/config.rs index 885dbc7f..18b0e492 100644 --- a/src/config.rs +++ b/src/config.rs @@ -1,4 +1,4 @@ -use super::internal::{Bounded, Infinite, SizeLimit}; +use super::internal::{Bounded, Infinite, SizeLimit, SizeType, U16, U32, U64, U8}; use byteorder::{BigEndian, ByteOrder, LittleEndian, NativeEndian}; use de::read::BincodeRead; use error::Result; @@ -7,14 +7,13 @@ use std::io::{Read, Write}; use std::marker::PhantomData; use {DeserializerAcceptor, SerializerAcceptor}; -use self::EndianOption::*; -use self::LimitOption::*; - struct DefaultOptions(Infinite); pub(crate) trait Options { type Limit: SizeLimit + 'static; type Endian: ByteOrder + 'static; + type StringSize: SizeType + 'static; + type ArraySize: SizeType + 'static; fn limit(&mut self) -> &mut Self::Limit; } @@ -39,11 +38,27 @@ pub(crate) trait OptionsExt: Options + Sized { fn with_native_endian(self) -> WithOtherEndian { WithOtherEndian::new(self) } + + fn with_string_size(self) -> WithOtherStringLength + where + S: SizeType, + { + WithOtherStringLength::new(self) + } + + fn with_array_size(self) -> WithOtherArrayLength + where + S: SizeType, + { + WithOtherArrayLength::new(self) + } } impl<'a, O: Options> Options for &'a mut O { type Limit = O::Limit; type Endian = O::Endian; + type StringSize = O::StringSize; + type ArraySize = O::ArraySize; #[inline(always)] fn limit(&mut self) -> &mut Self::Limit { @@ -62,6 +77,8 @@ impl DefaultOptions { impl Options for DefaultOptions { type Limit = Infinite; type Endian = LittleEndian; + type StringSize = U64; + type ArraySize = U64; #[inline(always)] fn limit(&mut self) -> &mut Infinite { @@ -82,6 +99,19 @@ enum EndianOption { Native, } +/// Used to specify the unit used for length of strings and arrays via `config.string_length` or `config.array_length`. +#[derive(Clone, Copy)] +pub enum LengthOption { + ///64 unsigned bits + U64, + ///32 unsigned bits + U32, + ///16 unsigned bits + U16, + ///8 unsigned bits + U8, +} + /// A configuration builder whose options Bincode will use /// while serializing and deserializing. /// @@ -95,10 +125,19 @@ enum EndianOption { /// /// When a byte limit is set, bincode will return `Err` on any deserialization that goes over the limit, or any /// serialization that goes over the limit. +/// ### Array and String sizes +/// When writing a string or an array is serialized the length is written at the beginning so that the data +/// can be deserialized. The option is a way to configure how this length is encoded. The default for both +/// is `U64`. +/// +/// If a string or array is attempted to be serialized that is not fit within the type specified bincode will return `Err` +/// on serialization. #[derive(Clone)] pub struct Config { limit: LimitOption, endian: EndianOption, + string_size: LengthOption, + array_size: LengthOption, } pub(crate) struct WithOtherLimit { @@ -111,6 +150,16 @@ pub(crate) struct WithOtherEndian { _endian: PhantomData, } +pub(crate) struct WithOtherStringLength { + options: O, + _new_string_length: PhantomData, +} + +pub(crate) struct WithOtherArrayLength { + options: O, + _new_array_length: PhantomData, +} + impl WithOtherLimit { #[inline(always)] pub(crate) fn new(options: O, limit: L) -> WithOtherLimit { @@ -131,9 +180,31 @@ impl WithOtherEndian { } } +impl WithOtherStringLength { + #[inline(always)] + pub(crate) fn new(options: O) -> WithOtherStringLength { + WithOtherStringLength { + options: options, + _new_string_length: PhantomData, + } + } +} + +impl WithOtherArrayLength { + #[inline(always)] + pub(crate) fn new(options: O) -> WithOtherArrayLength { + WithOtherArrayLength { + options: options, + _new_array_length: PhantomData, + } + } +} + impl Options for WithOtherEndian { type Limit = O::Limit; type Endian = E; + type StringSize = O::StringSize; + type ArraySize = O::ArraySize; #[inline(always)] fn limit(&mut self) -> &mut O::Limit { @@ -144,50 +215,134 @@ impl Options for WithOtherEndian { impl Options for WithOtherLimit { type Limit = L; type Endian = O::Endian; + type StringSize = O::StringSize; + type ArraySize = O::ArraySize; fn limit(&mut self) -> &mut L { &mut self.new_limit } } -macro_rules! config_map { +impl Options for WithOtherStringLength { + type Limit = O::Limit; + type Endian = O::Endian; + type StringSize = L; + type ArraySize = O::ArraySize; + + fn limit(&mut self) -> &mut O::Limit { + self.options.limit() + } +} + +impl Options for WithOtherArrayLength { + type Limit = O::Limit; + type Endian = O::Endian; + type StringSize = O::StringSize; + type ArraySize = L; + + fn limit(&mut self) -> &mut O::Limit { + self.options.limit() + } +} + +macro_rules! config_map_limit { + ($self:expr, $opts:ident => $call:expr) => { + match $self.limit { + LimitOption::Unlimited => { + let $opts = $opts.with_no_limit(); + $call + } + LimitOption::Limited(l) => { + let $opts = $opts.with_limit(l); + $call + } + } + }; +} + +macro_rules! config_map_endian { ($self:expr, $opts:ident => $call:expr) => { - match ($self.limit, $self.endian) { - (Unlimited, Little) => { - let $opts = DefaultOptions::new().with_no_limit().with_little_endian(); + match $self.endian { + EndianOption::Little => { + let $opts = $opts.with_little_endian(); $call } - (Unlimited, Big) => { - let $opts = DefaultOptions::new().with_no_limit().with_big_endian(); + EndianOption::Big => { + let $opts = $opts.with_big_endian(); $call } - (Unlimited, Native) => { - let $opts = DefaultOptions::new().with_no_limit().with_native_endian(); + EndianOption::Native => { + let $opts = $opts.with_native_endian(); $call } + } + }; +} - (Limited(l), Little) => { - let $opts = DefaultOptions::new().with_limit(l).with_little_endian(); +macro_rules! config_map_string_length { + ($self:expr, $opts:ident => $call:expr) => { + match $self.string_size { + LengthOption::U64 => { + let $opts = $opts.with_string_size::(); $call } - (Limited(l), Big) => { - let $opts = DefaultOptions::new().with_limit(l).with_big_endian(); + LengthOption::U32 => { + let $opts = $opts.with_string_size::(); $call } - (Limited(l), Native) => { - let $opts = DefaultOptions::new().with_limit(l).with_native_endian(); + LengthOption::U16 => { + let $opts = $opts.with_string_size::(); + $call + } + LengthOption::U8 => { + let $opts = $opts.with_string_size::(); $call } } }; } +macro_rules! config_map_array_length { + ($self:expr, $opts:ident => $call:expr) => { + match $self.array_size { + LengthOption::U64 => { + let $opts = $opts.with_array_size::(); + $call + } + LengthOption::U32 => { + let $opts = $opts.with_array_size::(); + $call + } + LengthOption::U16 => { + let $opts = $opts.with_array_size::(); + $call + } + LengthOption::U8 => { + let $opts = $opts.with_array_size::(); + $call + } + } + }; +} + +macro_rules! config_map { + ($self:expr, $opts:ident => $call:expr) => {{ + let $opts = DefaultOptions::new(); + config_map_limit!($self, $opts => + config_map_endian!($self, $opts => + config_map_string_length!($self, $opts => + config_map_array_length!($self, $opts => $call)))) + }} +} + impl Config { #[inline(always)] pub(crate) fn new() -> Config { Config { limit: LimitOption::Unlimited, endian: EndianOption::Little, + string_size: LengthOption::U64, + array_size: LengthOption::U64, } } @@ -228,6 +383,20 @@ impl Config { self } + /// Sets the size used for lengths of strings + #[inline(always)] + pub fn string_length(&mut self, size: LengthOption) -> &mut Self { + self.string_size = size; + self + } + + /// Sets the size used for lengths of arrays + #[inline(always)] + pub fn array_length(&mut self, size: LengthOption) -> &mut Self { + self.array_size = size; + self + } + /// Serializes a serializable object into a `Vec` of bytes using this configuration #[inline(always)] pub fn serialize(&self, t: &T) -> Result> { diff --git a/src/de/mod.rs b/src/de/mod.rs index efe11613..b5cbf7ac 100644 --- a/src/de/mod.rs +++ b/src/de/mod.rs @@ -1,9 +1,11 @@ use config::Options; use std::io::Read; +use super::try_into::*; use self::read::BincodeRead; use byteorder::ReadBytesExt; use internal::SizeLimit; +use internal::SizeType; use serde; use serde::de::Error as DeError; use serde::de::IntoDeserializer; @@ -48,13 +50,17 @@ impl<'de, R: BincodeRead<'de>, O: Options> Deserializer { } fn read_vec(&mut self) -> Result> { - let len: usize = try!(serde::Deserialize::deserialize(&mut *self)); - self.read_bytes(len as u64)?; + let len = O::ArraySize::read(&mut || serde::Deserialize::deserialize(&mut *self))?; + self.read_bytes(len)?; + let len: usize = len.try_into().map_err(|_e| ErrorKind::SizeLimit)?; self.reader.get_byte_buffer(len) } fn read_string(&mut self) -> Result { - let vec = self.read_vec()?; + let len = O::StringSize::read(&mut || serde::Deserialize::deserialize(&mut *self))?; + self.read_bytes(len)?; + let len: usize = len.try_into().map_err(|_e| ErrorKind::SizeLimit)?; + let vec = self.reader.get_byte_buffer(len)?; String::from_utf8(vec).map_err(|e| ErrorKind::InvalidUtf8Encoding(e.utf8_error()).into()) } } @@ -183,12 +189,10 @@ where return Err(error()); } - let res = try!( - str::from_utf8(&buf[..width]) - .ok() - .and_then(|s| s.chars().next()) - .ok_or(error()) - ); + let res = try!(str::from_utf8(&buf[..width]) + .ok() + .and_then(|s| s.chars().next()) + .ok_or(error())); visitor.visit_char(res) } @@ -196,8 +200,9 @@ where where V: serde::de::Visitor<'de>, { - let len: usize = try!(serde::Deserialize::deserialize(&mut *self)); - try!(self.read_bytes(len as u64)); + let len = O::StringSize::read(&mut || serde::Deserialize::deserialize(&mut *self))?; + try!(self.read_bytes(len)); + let len: usize = len.try_into().map_err(|_e| ErrorKind::SizeLimit)?; self.reader.forward_read_str(len, visitor) } @@ -212,8 +217,9 @@ where where V: serde::de::Visitor<'de>, { - let len: usize = try!(serde::Deserialize::deserialize(&mut *self)); - try!(self.read_bytes(len as u64)); + let len = O::ArraySize::read(&mut || serde::Deserialize::deserialize(&mut *self))?; + try!(self.read_bytes(len)); + let len: usize = len.try_into().map_err(|_e| ErrorKind::SizeLimit)?; self.reader.forward_read_bytes(len, visitor) } @@ -311,8 +317,8 @@ where where V: serde::de::Visitor<'de>, { - let len = try!(serde::Deserialize::deserialize(&mut *self)); - + let len = O::ArraySize::read(&mut || serde::Deserialize::deserialize(&mut *self))?; + let len: usize = len.try_into().map_err(|_e| ErrorKind::SizeLimit)?; self.deserialize_tuple(len, visitor) } @@ -362,8 +368,8 @@ where } } - let len = try!(serde::Deserialize::deserialize(&mut *self)); - + let len = O::ArraySize::read(&mut || serde::Deserialize::deserialize(&mut *self))?; + let len: usize = len.try_into().map_err(|_e| ErrorKind::SizeLimit)?; visitor.visit_map(Access { deserializer: self, len: len, diff --git a/src/de/read.rs b/src/de/read.rs index ffc5ae2a..92f900c1 100644 --- a/src/de/read.rs +++ b/src/de/read.rs @@ -145,9 +145,7 @@ where // Then create a slice with the length as our desired length. This is // safe as long as we only write (no reads) to this buffer, because // `reserve_exact` above has allocated this space. - let buf = unsafe { - slice::from_raw_parts_mut(self.temp_buffer.as_mut_ptr(), length) - }; + let buf = unsafe { slice::from_raw_parts_mut(self.temp_buffer.as_mut_ptr(), length) }; // This method is assumed to properly handle slices which include // uninitialized bytes (as ours does). See discussion at the link below. diff --git a/src/error.rs b/src/error.rs index 1f52424c..ae06cb84 100644 --- a/src/error.rs +++ b/src/error.rs @@ -33,6 +33,8 @@ pub enum ErrorKind { /// If (de)serializing a message takes more than the provided size limit, this /// error is returned. SizeLimit, + /// If serializing a string/vec/array requires more bytes to represent the size than the config allows. + SizeTypeLimit, /// Bincode can not encode sequences of unknown length (like iterators). SequenceMustHaveLength, /// A custom error message from Serde. @@ -54,6 +56,9 @@ impl StdError for ErrorKind { "Bincode doesn't support serde::Deserializer::deserialize_any" } ErrorKind::SizeLimit => "the size limit has been reached", + ErrorKind::SizeTypeLimit => { + "the size is larger than can be represented with this config" + } ErrorKind::Custom(ref msg) => msg, } } @@ -68,6 +73,7 @@ impl StdError for ErrorKind { ErrorKind::SequenceMustHaveLength => None, ErrorKind::DeserializeAnyNotSupported => None, ErrorKind::SizeLimit => None, + ErrorKind::SizeTypeLimit => None, ErrorKind::Custom(_) => None, } } @@ -93,6 +99,7 @@ impl fmt::Display for ErrorKind { } ErrorKind::SequenceMustHaveLength => write!(fmt, "{}", self.description()), ErrorKind::SizeLimit => write!(fmt, "{}", self.description()), + ErrorKind::SizeTypeLimit => write!(fmt, "{}", self.description()), ErrorKind::DeserializeAnyNotSupported => write!( fmt, "Bincode does not support the serde::Deserializer::deserialize_any method" diff --git a/src/internal.rs b/src/internal.rs index 968950a3..0bdb9aa4 100644 --- a/src/internal.rs +++ b/src/internal.rs @@ -5,6 +5,7 @@ use std::marker::PhantomData; use config::{Options, OptionsExt}; use de::read::BincodeRead; use {ErrorKind, Result}; +use try_into::*; #[derive(Clone)] struct CountSize { @@ -189,3 +190,82 @@ impl SizeLimit for Infinite { None } } + +pub(crate) trait SizeType: Clone { + type Primitive: serde::de::DeserializeOwned + TryFrom + Into; + + fn read(reader: &mut FnMut() -> Result) -> Result { + let result: Self::Primitive = reader()?; + Ok(result.into()) + } + + fn write(writer: S, value: usize) -> Result + where + S: serde::Serializer, + Box: From, + { + let value: Self::Primitive = value.try_into().map_err(|_e| ErrorKind::SizeTypeLimit)?; + Self::write_to(writer, value) + } + + fn write_to(writer: S, value: Self::Primitive) -> Result + where + S: serde::Serializer, + Box: From; +} + +/// An 8 byte length +#[derive(Copy, Clone)] +pub struct U64; +impl SizeType for U64 { + type Primitive = u64; + fn write_to(writer: S, value: Self::Primitive) -> Result + where + S: serde::Serializer, + Box: From, + { + writer.serialize_u64(value).map_err(Into::into) + } +} + +/// A 4 byte length +#[derive(Copy, Clone)] +pub struct U32; +impl SizeType for U32 { + type Primitive = u32; + fn write_to(writer: S, value: Self::Primitive) -> Result + where + S: serde::Serializer, + Box: From, + { + writer.serialize_u32(value).map_err(Into::into) + } +} + +/// A 2 byte length +#[derive(Copy, Clone)] +pub struct U16; +impl SizeType for U16 { + type Primitive = u16; + fn write_to(writer: S, value: Self::Primitive) -> Result + where + S: serde::Serializer, + Box: From, + { + writer.serialize_u16(value).map_err(Into::into) + } +} + +/// A 1 byte length +#[derive(Copy, Clone)] +pub struct U8; +impl SizeType for U8 { + type Primitive = u8; + fn write_to(writer: S, value: Self::Primitive) -> Result + where + S: serde::Serializer, + Box: From, + { + writer.serialize_u8(value).map_err(Into::into) + } +} diff --git a/src/lib.rs b/src/lib.rs index ed8e327f..0c4d60e2 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -37,8 +37,9 @@ mod de; mod error; mod internal; mod ser; +mod try_into; -pub use config::Config; +pub use config::{Config, LengthOption}; pub use de::read::{BincodeRead, IoReader, SliceReader}; pub use error::{Error, ErrorKind, Result}; diff --git a/src/ser/mod.rs b/src/ser/mod.rs index 4604c3e6..ada219d5 100644 --- a/src/ser/mod.rs +++ b/src/ser/mod.rs @@ -6,6 +6,7 @@ use serde; use byteorder::WriteBytesExt; use super::internal::SizeLimit; +use super::internal::SizeType; use super::{Error, ErrorKind, Result}; use config::Options; @@ -125,7 +126,7 @@ impl<'a, W: Write, O: Options> serde::Serializer for &'a mut Serializer { } fn serialize_str(self, v: &str) -> Result<()> { - try!(self.serialize_u64(v.len() as u64)); + O::StringSize::write(&mut *self, v.len())?; self.writer.write_all(v.as_bytes()).map_err(Into::into) } @@ -136,7 +137,7 @@ impl<'a, W: Write, O: Options> serde::Serializer for &'a mut Serializer { } fn serialize_bytes(self, v: &[u8]) -> Result<()> { - try!(self.serialize_u64(v.len() as u64)); + O::ArraySize::write(&mut *self, v.len())?; self.writer.write_all(v).map_err(Into::into) } @@ -153,8 +154,8 @@ impl<'a, W: Write, O: Options> serde::Serializer for &'a mut Serializer { } fn serialize_seq(self, len: Option) -> Result { - let len = try!(len.ok_or(ErrorKind::SequenceMustHaveLength)); - try!(self.serialize_u64(len as u64)); + let len = len.ok_or(ErrorKind::SequenceMustHaveLength)?; + O::ArraySize::write(&mut *self, len)?; Ok(Compound { ser: self }) } @@ -182,8 +183,8 @@ impl<'a, W: Write, O: Options> serde::Serializer for &'a mut Serializer { } fn serialize_map(self, len: Option) -> Result { - let len = try!(len.ok_or(ErrorKind::SequenceMustHaveLength)); - try!(self.serialize_u64(len as u64)); + let len = len.ok_or(ErrorKind::SequenceMustHaveLength)?; + O::ArraySize::write(&mut *self, len)?; Ok(Compound { ser: self }) } @@ -242,9 +243,6 @@ pub(crate) struct SizeChecker { } impl SizeChecker { - pub fn new(options: O) -> SizeChecker { - SizeChecker { options: options } - } fn add_raw(&mut self, size: u64) -> Result<()> { self.options.limit().add(size) @@ -330,7 +328,7 @@ impl<'a, O: Options> serde::Serializer for &'a mut SizeChecker { } fn serialize_str(self, v: &str) -> Result<()> { - try!(self.add_value(0 as u64)); + O::StringSize::write(&mut *self, v.len())?; self.add_raw(v.len() as u64) } @@ -339,7 +337,7 @@ impl<'a, O: Options> serde::Serializer for &'a mut SizeChecker { } fn serialize_bytes(self, v: &[u8]) -> Result<()> { - try!(self.add_value(0 as u64)); + O::ArraySize::write(&mut *self, v.len())?; self.add_raw(v.len() as u64) } @@ -356,9 +354,8 @@ impl<'a, O: Options> serde::Serializer for &'a mut SizeChecker { } fn serialize_seq(self, len: Option) -> Result { - let len = try!(len.ok_or(ErrorKind::SequenceMustHaveLength)); - - try!(self.serialize_u64(len as u64)); + let len = len.ok_or(ErrorKind::SequenceMustHaveLength)?; + O::ArraySize::write(&mut *self, len)?; Ok(SizeCompound { ser: self }) } @@ -386,9 +383,8 @@ impl<'a, O: Options> serde::Serializer for &'a mut SizeChecker { } fn serialize_map(self, len: Option) -> Result { - let len = try!(len.ok_or(ErrorKind::SequenceMustHaveLength)); - - try!(self.serialize_u64(len as u64)); + let len = len.ok_or(ErrorKind::SequenceMustHaveLength)?; + O::ArraySize::write(&mut *self, len)?; Ok(SizeCompound { ser: self }) } diff --git a/src/try_into.rs b/src/try_into.rs new file mode 100644 index 00000000..52b3f6c5 --- /dev/null +++ b/src/try_into.rs @@ -0,0 +1,216 @@ +///For whatever reason bincode is stuck in Rust 1.18, so this module replicates some of the +///functionality of try_from / try_into from the standard library. THERE IS NO ORIGINAL CODE HERE +pub(crate) trait TryFrom: Sized { + /// The type returned in the event of a conversion error. + type Error; + + /// Performs the conversion. + fn try_from(value: T) -> Result; +} + +pub(crate) trait TryInto: Sized { + /// The type returned in the event of a conversion error. + type Error; + + /// Performs the conversion. + fn try_into(self) -> Result; +} + +// TryFrom implies TryInto +impl TryInto for T where U: TryFrom +{ + type Error = U::Error; + + fn try_into(self) -> Result { + U::try_from(self) + } +} + +pub(crate) struct TryFromIntError(()); + +// no possible bounds violation +macro_rules! try_from_unbounded { + ($source:ty, $($target:ty),*) => {$( + impl TryFrom<$source> for $target { + type Error = TryFromIntError; + + /// Try to create the target number type from a source + /// number type. This returns an error if the source value + /// is outside of the range of the target type. + #[inline] + fn try_from(value: $source) -> Result { + Ok(value as $target) + } + } + )*} +} + +// only negative bounds +macro_rules! try_from_lower_bounded { + ($source:ty, $($target:ty),*) => {$( + impl TryFrom<$source> for $target { + type Error = TryFromIntError; + + /// Try to create the target number type from a source + /// number type. This returns an error if the source value + /// is outside of the range of the target type. + #[inline] + fn try_from(u: $source) -> Result<$target, TryFromIntError> { + if u >= 0 { + Ok(u as $target) + } else { + Err(TryFromIntError(())) + } + } + } + )*} +} + +// unsigned to signed (only positive bound) +macro_rules! try_from_upper_bounded { + ($source:ty, $($target:ty),*) => {$( + impl TryFrom<$source> for $target { + type Error = TryFromIntError; + + /// Try to create the target number type from a source + /// number type. This returns an error if the source value + /// is outside of the range of the target type. + #[inline] + fn try_from(u: $source) -> Result<$target, TryFromIntError> { + if u > (<$target>::max_value() as $source) { + Err(TryFromIntError(())) + } else { + Ok(u as $target) + } + } + } + )*} +} + +// all other cases +macro_rules! try_from_both_bounded { + ($source:ty, $($target:ty),*) => {$( + impl TryFrom<$source> for $target { + type Error = TryFromIntError; + + /// Try to create the target number type from a source + /// number type. This returns an error if the source value + /// is outside of the range of the target type. + #[inline] + fn try_from(u: $source) -> Result<$target, TryFromIntError> { + let min = <$target>::min_value() as $source; + let max = <$target>::max_value() as $source; + if u < min || u > max { + Err(TryFromIntError(())) + } else { + Ok(u as $target) + } + } + } + )*} +} + +macro_rules! rev { + ($mac:ident, $source:ty, $($target:ty),*) => {$( + $mac!($target, $source); + )*} +} + +// intra-sign conversions +try_from_upper_bounded!(u16, u8); +try_from_upper_bounded!(u32, u16, u8); +try_from_upper_bounded!(u64, u32, u16, u8); + +try_from_both_bounded!(i16, i8); +try_from_both_bounded!(i32, i16, i8); +try_from_both_bounded!(i64, i32, i16, i8); + +// unsigned-to-signed +try_from_upper_bounded!(u8, i8); +try_from_upper_bounded!(u16, i8, i16); +try_from_upper_bounded!(u32, i8, i16, i32); +try_from_upper_bounded!(u64, i8, i16, i32, i64); + +// signed-to-unsigned +try_from_lower_bounded!(i8, u8, u16, u32, u64); +try_from_lower_bounded!(i16, u16, u32, u64); +try_from_lower_bounded!(i32, u32, u64); +try_from_lower_bounded!(i64, u64); +try_from_both_bounded!(i16, u8); +try_from_both_bounded!(i32, u16, u8); +try_from_both_bounded!(i64, u32, u16, u8); + +// usize/isize +try_from_upper_bounded!(usize, isize); +try_from_lower_bounded!(isize, usize); + +#[cfg(target_pointer_width = "16")] +mod ptr_try_from_impls { + use super::TryFromIntError; + use super::TryFrom; + + try_from_upper_bounded!(usize, u8); + try_from_unbounded!(usize, u16, u32, u64); + try_from_upper_bounded!(usize, i8, i16); + try_from_unbounded!(usize, i32, i64); + + try_from_both_bounded!(isize, u8); + try_from_lower_bounded!(isize, u16, u32, u64); + try_from_both_bounded!(isize, i8); + try_from_unbounded!(isize, i16, i32, i64); + + rev!(try_from_upper_bounded, usize, u32, u64); + rev!(try_from_lower_bounded, usize, i8, i16); + rev!(try_from_both_bounded, usize, i32, i64); + + rev!(try_from_upper_bounded, isize, u16, u32, u64); + rev!(try_from_both_bounded, isize, i32, i64); +} + +#[cfg(target_pointer_width = "32")] +mod ptr_try_from_impls { + use super::TryFromIntError; + use super::TryFrom; + + try_from_upper_bounded!(usize, u8, u16); + try_from_unbounded!(usize, u32, u64); + try_from_upper_bounded!(usize, i8, i16, i32); + try_from_unbounded!(usize, i64); + + try_from_both_bounded!(isize, u8, u16); + try_from_lower_bounded!(isize, u32, u64); + try_from_both_bounded!(isize, i8, i16); + try_from_unbounded!(isize, i32, i64); + + rev!(try_from_unbounded, usize, u32); + rev!(try_from_upper_bounded, usize, u64); + rev!(try_from_lower_bounded, usize, i8, i16, i32); + rev!(try_from_both_bounded, usize, i64); + + rev!(try_from_unbounded, isize, u16); + rev!(try_from_upper_bounded, isize, u32, u64); + rev!(try_from_unbounded, isize, i32); + rev!(try_from_both_bounded, isize, i64); +} + +#[cfg(target_pointer_width = "64")] +mod ptr_try_from_impls { + use super::TryFromIntError; + use super::TryFrom; + + try_from_upper_bounded!(usize, u8, u16, u32); + try_from_unbounded!(usize, u64); + try_from_upper_bounded!(usize, i8, i16, i32, i64); + + try_from_both_bounded!(isize, u8, u16, u32); + try_from_lower_bounded!(isize, u64); + try_from_both_bounded!(isize, i8, i16, i32); + try_from_unbounded!(isize, i64); + + rev!(try_from_unbounded, usize, u32, u64); + rev!(try_from_lower_bounded, usize, i8, i16, i32, i64); + + rev!(try_from_unbounded, isize, u16, u32); + rev!(try_from_upper_bounded, isize, u64); + rev!(try_from_unbounded, isize, i32, i64); +} diff --git a/tests/test.rs b/tests/test.rs index 33735254..89c899b6 100644 --- a/tests/test.rs +++ b/tests/test.rs @@ -13,10 +13,38 @@ use std::result::Result as StdResult; use bincode::{ config, deserialize, deserialize_from, deserialize_in_place, serialize, serialized_size, - ErrorKind, Result, + ErrorKind, LengthOption, Result, }; use serde::de::{Deserialize, DeserializeSeed, Deserializer, SeqAccess, Visitor}; +#[test] +fn test_numbers() { + // unsigned positive + the_same(5u8); + the_same(5u16); + the_same(5u32); + the_same(5u64); + the_same(5usize); + // signed positive + the_same(5i8); + the_same(5i16); + the_same(5i32); + the_same(5i64); + the_same(5isize); + // signed negative + the_same(-5i8); + the_same(-5i16); + the_same(-5i32); + the_same(-5i64); + the_same(-5isize); + // floating + the_same(-100f32); + the_same(0f32); + the_same(5f32); + the_same(-100f64); + the_same(5f64); +} + fn the_same(element: V) where V: serde::Serialize + serde::de::DeserializeOwned + PartialEq + Debug + 'static, @@ -44,32 +72,62 @@ where assert_eq!(size, encoded.len() as u64); } } -#[test] -fn test_numbers() { - // unsigned positive - the_same(5u8); - the_same(5u16); - the_same(5u32); - the_same(5u64); - the_same(5usize); - // signed positive - the_same(5i8); - the_same(5i16); - the_same(5i32); - the_same(5i64); - the_same(5isize); - // signed negative - the_same(-5i8); - the_same(-5i16); - the_same(-5i32); - the_same(-5i64); - the_same(-5isize); - // floating - the_same(-100f32); - the_same(0f32); - the_same(5f32); - the_same(-100f64); - the_same(5f64); + +fn the_same_str(element: String) { + let with_length = |length: LengthOption| { + let size = config() + .string_length(length) + .serialized_size(&element) + .unwrap(); + let encoded = config().string_length(length).serialize(&element).unwrap(); + let decoded: String = config() + .string_length(length) + .deserialize(&encoded[..]) + .unwrap(); + let decoded_reader: String = config() + .string_length(length) + .deserialize_from(&mut &encoded[..]) + .unwrap(); + + assert_eq!(element, decoded); + assert_eq!(element, decoded_reader); + assert_eq!(size, encoded.len() as u64); + }; + with_length(LengthOption::U64); + with_length(LengthOption::U32); + with_length(LengthOption::U16); + with_length(LengthOption::U8); + the_same(element); +} + +fn the_same_vec(element: Vec) +where + T: serde::Serialize + serde::de::DeserializeOwned + PartialEq + Debug + 'static, +{ + let with_length = |length: LengthOption| { + let size = config() + .string_length(length) + .serialized_size(&element) + .unwrap(); + let encoded = config().string_length(length).serialize(&element).unwrap(); + let decoded: Vec = config() + .string_length(length) + .deserialize(&encoded[..]) + .unwrap(); + let decoded_reader: Vec = config() + .string_length(length) + .deserialize_from(&mut &encoded[..]) + .unwrap(); + + assert_eq!(element, decoded); + assert_eq!(element, decoded_reader); + assert_eq!(size, encoded.len() as u64); + }; + with_length(LengthOption::U64); + with_length(LengthOption::U32); + with_length(LengthOption::U16); + with_length(LengthOption::U8); + the_same(element); } #[cfg(has_i128)] @@ -88,8 +146,8 @@ fn test_numbers_128bit() { #[test] fn test_string() { - the_same("".to_string()); - the_same("a".to_string()); + the_same_str("".to_string()); + the_same_str("a".to_string()); } #[test] @@ -193,9 +251,9 @@ fn test_enum() { #[test] fn test_vec() { let v: Vec = vec![]; - the_same(v); - the_same(vec![1u64]); - the_same(vec![1u64, 2, 3, 4, 5, 6]); + the_same_vec(v); + the_same_vec(vec![1u64]); + the_same_vec(vec![1u64, 2, 3, 4, 5, 6]); } #[test] @@ -214,8 +272,8 @@ fn test_bool() { #[test] fn test_unicode() { - the_same("å".to_string()); - the_same("aåååååååa".to_string()); + the_same_str("å".to_string()); + the_same_str("aåååååååa".to_string()); } #[test] @@ -332,12 +390,10 @@ fn test_serialized_size_bounded() { assert!(config().limit(7).serialized_size(&0u64).is_err()); assert!(config().limit(7).serialized_size(&"").is_err()); assert!(config().limit(8 + 0).serialized_size(&"a").is_err()); - assert!( - config() - .limit(8 + 3 * 4 - 1) - .serialized_size(&vec![0u32, 1u32, 2u32]) - .is_err() - ); + assert!(config() + .limit(8 + 3 * 4 - 1) + .serialized_size(&vec![0u32, 1u32, 2u32]) + .is_err()); } #[test] @@ -421,11 +477,16 @@ fn test_oom_protection() { .serialize(&FakeVec { len: 0xffffffffffffffffu64, byte: 1, - }).unwrap(); + }) + .unwrap(); let y: Result> = config() .limit(10) .deserialize_from(&mut Cursor::new(&x[..])); assert!(y.is_err()); + let y: Result = config() + .limit(10) + .deserialize_from(&mut Cursor::new(&x[..])); + assert!(y.is_err()); } #[test] @@ -579,7 +640,8 @@ fn test_zero_copy_parse_deserialize_into() { slice: &encoded[..], }, &mut target, - ).unwrap(); + ) + .unwrap(); assert_eq!(target, f); } } @@ -716,3 +778,111 @@ fn test_big_endian_deserialize_from_seed() { assert_eq!(seed_data, (0..100).collect::>()); } + +#[test] +fn test_str_size() { + let str = "abcd"; + the_same_str(str.to_owned()); + let expected = config().serialized_size(str).unwrap(); + let actual = config().serialize(str).unwrap().len(); + assert_eq!(12, expected); + assert_eq!(12, actual); + let expected = config() + .string_length(LengthOption::U64) + .serialized_size(str) + .unwrap(); + let actual = config() + .string_length(LengthOption::U64) + .serialize(str) + .unwrap() + .len(); + assert_eq!(12, expected); + assert_eq!(12, actual); + let expected = config() + .string_length(LengthOption::U32) + .serialized_size(str) + .unwrap(); + let actual = config() + .string_length(LengthOption::U32) + .serialize(str) + .unwrap() + .len(); + assert_eq!(8, expected); + assert_eq!(8, actual); + let expected = config() + .string_length(LengthOption::U16) + .serialized_size(str) + .unwrap(); + let actual = config() + .string_length(LengthOption::U16) + .serialize(str) + .unwrap() + .len(); + assert_eq!(6, expected); + assert_eq!(6, actual); + let expected = config() + .string_length(LengthOption::U8) + .serialized_size(str) + .unwrap(); + let actual = config() + .string_length(LengthOption::U8) + .serialize(str) + .unwrap() + .len(); + assert_eq!(5, expected); + assert_eq!(5, actual); +} + +#[test] +fn test_vec_size() { + let v = vec![1u32, 2, 3, 4]; + the_same_vec(v.clone()); + let expected = config().serialized_size(&v).unwrap(); + let actual = config().serialize(&v).unwrap().len(); + assert_eq!(16 + 8, expected); + assert_eq!(16 + 8, actual); + let expected = config() + .array_length(LengthOption::U64) + .serialized_size(&v) + .unwrap(); + let actual = config() + .array_length(LengthOption::U64) + .serialize(&v) + .unwrap() + .len(); + assert_eq!(16 + 8, expected); + assert_eq!(16 + 8, actual); + let expected = config() + .array_length(LengthOption::U32) + .serialized_size(&v) + .unwrap(); + let actual = config() + .array_length(LengthOption::U32) + .serialize(&v) + .unwrap() + .len(); + assert_eq!(16 + 4, expected); + assert_eq!(16 + 4, actual); + let expected = config() + .array_length(LengthOption::U16) + .serialized_size(&v) + .unwrap(); + let actual = config() + .array_length(LengthOption::U16) + .serialize(&v) + .unwrap() + .len(); + assert_eq!(16 + 2, expected); + assert_eq!(16 + 2, actual); + let expected = config() + .array_length(LengthOption::U8) + .serialized_size(&v) + .unwrap(); + let actual = config() + .array_length(LengthOption::U8) + .serialize(&v) + .unwrap() + .len(); + assert_eq!(16 + 1, expected); + assert_eq!(16 + 1, actual); +}