diff --git a/src/config.rs b/src/config.rs index eeeae5a..191f5c3 100644 --- a/src/config.rs +++ b/src/config.rs @@ -4,6 +4,7 @@ use error::{ErrorKind, Result}; use serde; use std::io::{Read, Write}; use std::marker::PhantomData; +use std::mem::size_of; pub(crate) use self::internal::*; @@ -11,10 +12,9 @@ use self::EndianOption::*; use self::LimitOption::*; /// The default options for bincode serialization/deserialization. -/// Implements OptionsExt to allow building configuration object for non-default settings. /// /// ### Defaults -/// By default bincode will use little-endian encoding for mult-byte integers, and will not +/// By default bincode will use little-endian encoding for multi-byte integers, and will not /// limit the number of serialized/deserialized bytes. #[derive(Copy, Clone)] pub struct DefaultOptions(Infinite); @@ -38,9 +38,10 @@ impl Default for DefaultOptions { } } -impl Options for DefaultOptions { +impl InternalOptions for DefaultOptions { type Limit = Infinite; type Endian = LittleEndian; + type IntEncoding = FixintEncoding; #[inline(always)] fn limit(&mut self) -> &mut Infinite { @@ -64,7 +65,7 @@ impl Options for DefaultOptions { /// serialization that goes over the limit. /// Sets the byte limit to be unlimited. /// This is the default. -pub trait OptionsExt: Options + Sized { +pub trait Options: InternalOptions + Sized { /// Sets the byte limit to be unlimited. /// This is the default. fn with_no_limit(self) -> WithOtherLimit { @@ -92,6 +93,16 @@ pub trait OptionsExt: Options + Sized { WithOtherEndian::new(self) } + /// Sets the length encoding to varint + fn with_varint_encoding(self) -> WithOtherIntEncoding { + WithOtherIntEncoding::new(self) + } + + /// Sets the length encoding to be fixed + fn with_fixint_encoding(self) -> WithOtherIntEncoding { + WithOtherIntEncoding::new(self) + } + /// Serializes a serializable object into a `Vec` of bytes using this configuration #[inline(always)] fn serialize(self, t: &S) -> Result> { @@ -188,7 +199,7 @@ pub trait OptionsExt: Options + Sized { } } -impl OptionsExt for T {} +impl Options for T {} /// A SizeLimit that restricts serialized or deserialized messages from /// exceeding a certain byte length. @@ -253,6 +264,533 @@ impl BincodeByteOrder for NativeEndian { type Endian = byteorder::NativeEndian; } +/// Fixed-size integer encoding. +/// +/// * Fixed size integers are encoded directly +/// * Enum discriminants are encoded as u32 +/// * Lengths and usize are encoded as u64 +#[derive(Copy, Clone)] +pub struct FixintEncoding; + +/// Variable-size integer encoding (excepting [ui]8). +/// +/// Encoding an unsigned integer v (of any type excepting u8) works as follows: +/// +/// 1. If `u < 251`, encode it as a single byte with that value. +/// 2. If `251 <= u < 2**16`, encode it as a literal byte 251, followed by a u16 with value `u`. +/// 3. If `2**16 <= u < 2**32`, encode it as a literal byte 252, followed by a u32 with value `u`. +/// 4. If `2**32 <= u < 2**64`, encode it as a literal byte 253, followed by a u64 with value `u`. +/// 5. If `2**64 <= u < 2**128`, encode it as a literal byte 254, followed by a +/// u128 with value `u`. +/// +/// Then, for signed integers, we first convert to unsigned using the zigzag algorithm, +/// and then encode them as we do for unsigned integers generally. The reason we use this +/// algorithm is that it encodes those values which are close to zero in less bytes; the +/// obvious algorithm, where we encode the cast values, gives a very large encoding for all +/// negative values. +/// +/// The zigzag algorithm is defined as follows: +/// +/// ```ignore +/// fn zigzag(v: Signed) -> Unsigned { +/// match v { +/// 0 => 0, +/// v if v < 0 => |v| * 2 - 1 +/// v if v > 0 => v * 2 +/// } +/// } +/// ``` +/// +/// And works such that: +/// +/// ```ignore +/// assert_eq!(zigzag(0), 0); +/// assert_eq!(zigzag(-1), 1); +/// assert_eq!(zigzag(1), 2); +/// assert_eq!(zigzag(-2), 3); +/// assert_eq!(zigzag(2), 4); +/// assert_eq!(zigzag(i64::min_value()), u64::max_value()); +/// ``` +/// +/// Note that u256 and the like are unsupported by this format; if and when they are added to the +/// language, they may be supported via the extension point given by the 255 byte. +#[derive(Copy, Clone)] +pub struct VarintEncoding; + +const SINGLE_BYTE_MAX: u8 = 250; +const U16_BYTE: u8 = 251; +const U32_BYTE: u8 = 252; +const U64_BYTE: u8 = 253; +const U128_BYTE: u8 = 254; +const DESERIALIZE_EXTENSION_POINT_ERR: &str = r#" +Byte 255 is treated as an extension point; it should not be encoding anything. +Do you have a mismatched bincode version or configuration? +"#; + +impl VarintEncoding { + fn varint_size(n: u64) -> u64 { + if n <= SINGLE_BYTE_MAX as u64 { + 1 + } else if n <= u16::max_value() as u64 { + (1 + size_of::()) as u64 + } else if n <= u32::max_value() as u64 { + (1 + size_of::()) as u64 + } else { + (1 + size_of::()) as u64 + } + } + + #[inline(always)] + fn zigzag_encode(n: i64) -> u64 { + if n < 0 { + // let's avoid the edge case of i64::min_value() + // !n is equal to `-n - 1`, so this is: + // !n * 2 + 1 = 2(-n - 1) + 1 = -2n - 2 + 1 = -2n - 1 + !(n as u64) * 2 + 1 + } else { + (n as u64) * 2 + } + } + + #[inline(always)] + fn zigzag_decode(n: u64) -> i64 { + if n % 2 == 0 { + // positive number + (n / 2) as i64 + } else { + // negative number + // !m * 2 + 1 = n + // !m * 2 = n - 1 + // !m = (n - 1) / 2 + // m = !((n - 1) / 2) + // since we have n is odd, we have floor(n / 2) = floor((n - 1) / 2) + !(n / 2) as i64 + } + } + + fn serialize_varint( + ser: &mut ::ser::Serializer, + n: u64, + ) -> Result<()> { + if n <= SINGLE_BYTE_MAX as u64 { + ser.serialize_byte(n as u8) + } else if n <= u16::max_value() as u64 { + ser.serialize_byte(U16_BYTE)?; + ser.serialize_literal_u16(n as u16) + } else if n <= u32::max_value() as u64 { + ser.serialize_byte(U32_BYTE)?; + ser.serialize_literal_u32(n as u32) + } else { + ser.serialize_byte(U64_BYTE)?; + ser.serialize_literal_u64(n as u64) + } + } + + fn deserialize_varint<'de, R: BincodeRead<'de>, O: Options>( + de: &mut ::de::Deserializer, + ) -> Result { + #[allow(ellipsis_inclusive_range_patterns)] + match de.deserialize_byte()? { + byte @ 0...SINGLE_BYTE_MAX => Ok(byte as u64), + U16_BYTE => Ok(de.deserialize_literal_u16()? as u64), + U32_BYTE => Ok(de.deserialize_literal_u32()? as u64), + U64_BYTE => de.deserialize_literal_u64(), + U128_BYTE => Err(Box::new(ErrorKind::Custom( + "Invalid value (u128 range): you may have a version or configuration disagreement?" + .to_string(), + ))), + _ => Err(Box::new(ErrorKind::Custom( + DESERIALIZE_EXTENSION_POINT_ERR.to_string(), + ))), + } + } + + serde_if_integer128! { + // see zigzag_encode and zigzag_decode for implementation comments + #[inline(always)] + fn zigzag128_encode(n: i128) -> u128 { + if n < 0 { + !(n as u128) * 2 + 1 + } else { + (n as u128) * 2 + } + } + #[inline(always)] + fn zigzag128_decode(n: u128) -> i128 { + if n % 2 == 0 { + (n / 2) as i128 + } else { + !(n / 2) as i128 + } + } + + fn varint128_size(n: u128) -> u64 { + if n <= SINGLE_BYTE_MAX as u128 { + 1 + } else if n <= u16::max_value() as u128 { + (1 + size_of::()) as u64 + } else if n <= u32::max_value() as u128 { + (1 + size_of::()) as u64 + } else if n <= u64::max_value() as u128 { + (1 + size_of::()) as u64 + } else { + (1 + size_of::()) as u64 + } + } + + fn serialize_varint128( + ser: &mut ::ser::Serializer, + n: u128, + ) -> Result<()> { + if n <= SINGLE_BYTE_MAX as u128 { + ser.serialize_byte(n as u8) + } else if n <= u16::max_value() as u128 { + ser.serialize_byte(U16_BYTE)?; + ser.serialize_literal_u16(n as u16) + } else if n <= u32::max_value() as u128 { + ser.serialize_byte(U32_BYTE)?; + ser.serialize_literal_u32(n as u32) + } else if n <= u64::max_value() as u128 { + ser.serialize_byte(U64_BYTE)?; + ser.serialize_literal_u64(n as u64) + } else { + ser.serialize_byte(U128_BYTE)?; + ser.serialize_literal_u128(n) + } + } + + fn deserialize_varint128<'de, R: BincodeRead<'de>, O: Options>( + de: &mut ::de::Deserializer, + ) -> Result { + #[allow(ellipsis_inclusive_range_patterns)] + match de.deserialize_byte()? { + byte @ 0...SINGLE_BYTE_MAX => Ok(byte as u128), + U16_BYTE => Ok(de.deserialize_literal_u16()? as u128), + U32_BYTE => Ok(de.deserialize_literal_u32()? as u128), + U64_BYTE => Ok(de.deserialize_literal_u64()? as u128), + U128_BYTE => de.deserialize_literal_u128(), + _ => Err(Box::new(ErrorKind::Custom(DESERIALIZE_EXTENSION_POINT_ERR.to_string()))), + } + } + } +} + +fn cast_u64_to_usize(n: u64) -> Result { + if n <= usize::max_value() as u64 { + Ok(n as usize) + } else { + Err(Box::new(ErrorKind::Custom(format!( + "Invalid size {}: sizes must fit in a usize (0 to {})", + n, + usize::max_value() + )))) + } +} +fn cast_u64_to_u32(n: u64) -> Result { + if n <= u32::max_value() as u64 { + Ok(n as u32) + } else { + Err(Box::new(ErrorKind::Custom(format!( + "Invalid u32 {}: you may have a version disagreement?", + n, + )))) + } +} +fn cast_u64_to_u16(n: u64) -> Result { + if n <= u16::max_value() as u64 { + Ok(n as u16) + } else { + Err(Box::new(ErrorKind::Custom(format!( + "Invalid u16 {}: you may have a version disagreement?", + n, + )))) + } +} + +fn cast_i64_to_i32(n: i64) -> Result { + if n <= i32::max_value() as i64 && n >= i32::min_value() as i64 { + Ok(n as i32) + } else { + Err(Box::new(ErrorKind::Custom(format!( + "Invalid i32 {}: you may have a version disagreement?", + n, + )))) + } +} +fn cast_i64_to_i16(n: i64) -> Result { + if n <= i16::max_value() as i64 && n >= i16::min_value() as i64 { + Ok(n as i16) + } else { + Err(Box::new(ErrorKind::Custom(format!( + "Invalid i16 {}: you may have a version disagreement?", + n, + )))) + } +} + +impl IntEncoding for FixintEncoding { + #[inline(always)] + fn u16_size(_: u16) -> u64 { + size_of::() as u64 + } + #[inline(always)] + fn u32_size(_: u32) -> u64 { + size_of::() as u64 + } + #[inline(always)] + fn u64_size(_: u64) -> u64 { + size_of::() as u64 + } + + #[inline(always)] + fn i16_size(_: i16) -> u64 { + size_of::() as u64 + } + #[inline(always)] + fn i32_size(_: i32) -> u64 { + size_of::() as u64 + } + #[inline(always)] + fn i64_size(_: i64) -> u64 { + size_of::() as u64 + } + + #[inline(always)] + fn serialize_u16(ser: &mut ::Serializer, val: u16) -> Result<()> { + ser.serialize_literal_u16(val) + } + #[inline(always)] + fn serialize_u32(ser: &mut ::Serializer, val: u32) -> Result<()> { + ser.serialize_literal_u32(val) + } + #[inline(always)] + fn serialize_u64(ser: &mut ::Serializer, val: u64) -> Result<()> { + ser.serialize_literal_u64(val) + } + + #[inline(always)] + fn serialize_i16(ser: &mut ::Serializer, val: i16) -> Result<()> { + ser.serialize_literal_u16(val as u16) + } + #[inline(always)] + fn serialize_i32(ser: &mut ::Serializer, val: i32) -> Result<()> { + ser.serialize_literal_u32(val as u32) + } + #[inline(always)] + fn serialize_i64(ser: &mut ::Serializer, val: i64) -> Result<()> { + ser.serialize_literal_u64(val as u64) + } + + #[inline(always)] + fn deserialize_u16<'de, R: BincodeRead<'de>, O: Options>( + de: &mut ::Deserializer, + ) -> Result { + de.deserialize_literal_u16() + } + #[inline(always)] + fn deserialize_u32<'de, R: BincodeRead<'de>, O: Options>( + de: &mut ::Deserializer, + ) -> Result { + de.deserialize_literal_u32() + } + #[inline(always)] + fn deserialize_u64<'de, R: BincodeRead<'de>, O: Options>( + de: &mut ::Deserializer, + ) -> Result { + de.deserialize_literal_u64() + } + + #[inline(always)] + fn deserialize_i16<'de, R: BincodeRead<'de>, O: Options>( + de: &mut ::Deserializer, + ) -> Result { + Ok(de.deserialize_literal_u16()? as i16) + } + #[inline(always)] + fn deserialize_i32<'de, R: BincodeRead<'de>, O: Options>( + de: &mut ::Deserializer, + ) -> Result { + Ok(de.deserialize_literal_u32()? as i32) + } + #[inline(always)] + fn deserialize_i64<'de, R: BincodeRead<'de>, O: Options>( + de: &mut ::Deserializer, + ) -> Result { + Ok(de.deserialize_literal_u64()? as i64) + } + + serde_if_integer128! { + #[inline(always)] + fn u128_size(_: u128) -> u64{ + size_of::() as u64 + } + #[inline(always)] + fn i128_size(_: i128) -> u64{ + size_of::() as u64 + } + + #[inline(always)] + fn serialize_u128( + ser: &mut ::Serializer, + val: u128, + ) -> Result<()> { + ser.serialize_literal_u128(val) + } + #[inline(always)] + fn serialize_i128( + ser: &mut ::Serializer, + val: i128, + ) -> Result<()> { + ser.serialize_literal_u128(val as u128) + } + #[inline(always)] + fn deserialize_u128<'de, R: BincodeRead<'de>, O: Options>( + de: &mut ::Deserializer, + ) -> Result { + de.deserialize_literal_u128() + } + #[inline(always)] + fn deserialize_i128<'de, R: BincodeRead<'de>, O: Options>( + de: &mut ::Deserializer, + ) -> Result { + Ok(de.deserialize_literal_u128()? as i128) + } + } +} + +impl IntEncoding for VarintEncoding { + #[inline(always)] + fn u16_size(n: u16) -> u64 { + Self::varint_size(n as u64) + } + #[inline(always)] + fn u32_size(n: u32) -> u64 { + Self::varint_size(n as u64) + } + #[inline(always)] + fn u64_size(n: u64) -> u64 { + Self::varint_size(n) + } + + #[inline(always)] + fn i16_size(n: i16) -> u64 { + Self::varint_size(Self::zigzag_encode(n as i64)) + } + #[inline(always)] + fn i32_size(n: i32) -> u64 { + Self::varint_size(Self::zigzag_encode(n as i64)) + } + #[inline(always)] + fn i64_size(n: i64) -> u64 { + Self::varint_size(Self::zigzag_encode(n)) + } + + #[inline(always)] + fn serialize_u16(ser: &mut ::Serializer, val: u16) -> Result<()> { + Self::serialize_varint(ser, val as u64) + } + #[inline(always)] + fn serialize_u32(ser: &mut ::Serializer, val: u32) -> Result<()> { + Self::serialize_varint(ser, val as u64) + } + #[inline(always)] + fn serialize_u64(ser: &mut ::Serializer, val: u64) -> Result<()> { + Self::serialize_varint(ser, val) + } + + #[inline(always)] + fn serialize_i16(ser: &mut ::Serializer, val: i16) -> Result<()> { + Self::serialize_varint(ser, Self::zigzag_encode(val as i64)) + } + #[inline(always)] + fn serialize_i32(ser: &mut ::Serializer, val: i32) -> Result<()> { + Self::serialize_varint(ser, Self::zigzag_encode(val as i64)) + } + #[inline(always)] + fn serialize_i64(ser: &mut ::Serializer, val: i64) -> Result<()> { + Self::serialize_varint(ser, Self::zigzag_encode(val)) + } + + #[inline(always)] + fn deserialize_u16<'de, R: BincodeRead<'de>, O: Options>( + de: &mut ::Deserializer, + ) -> Result { + Self::deserialize_varint(de).and_then(cast_u64_to_u16) + } + #[inline(always)] + fn deserialize_u32<'de, R: BincodeRead<'de>, O: Options>( + de: &mut ::Deserializer, + ) -> Result { + Self::deserialize_varint(de).and_then(cast_u64_to_u32) + } + #[inline(always)] + fn deserialize_u64<'de, R: BincodeRead<'de>, O: Options>( + de: &mut ::Deserializer, + ) -> Result { + Self::deserialize_varint(de) + } + + #[inline(always)] + fn deserialize_i16<'de, R: BincodeRead<'de>, O: Options>( + de: &mut ::Deserializer, + ) -> Result { + Self::deserialize_varint(de) + .map(Self::zigzag_decode) + .and_then(cast_i64_to_i16) + } + #[inline(always)] + fn deserialize_i32<'de, R: BincodeRead<'de>, O: Options>( + de: &mut ::Deserializer, + ) -> Result { + Self::deserialize_varint(de) + .map(Self::zigzag_decode) + .and_then(cast_i64_to_i32) + } + #[inline(always)] + fn deserialize_i64<'de, R: BincodeRead<'de>, O: Options>( + de: &mut ::Deserializer, + ) -> Result { + Self::deserialize_varint(de).map(Self::zigzag_decode) + } + + serde_if_integer128! { + #[inline(always)] + fn u128_size(n: u128) -> u64 { + Self::varint128_size(n) + } + #[inline(always)] + fn i128_size(n: i128) -> u64 { + Self::varint128_size(Self::zigzag128_encode(n)) + } + #[inline(always)] + fn serialize_u128( + ser: &mut ::Serializer, + val: u128, + ) -> Result<()> { + Self::serialize_varint128(ser, val) + } + #[inline(always)] + fn serialize_i128( + ser: &mut ::Serializer, + val: i128, + ) -> Result<()> { + Self::serialize_varint128(ser, Self::zigzag128_encode(val)) + } + #[inline(always)] + fn deserialize_u128<'de, R: BincodeRead<'de>, O: Options>( + de: &mut ::Deserializer, + ) -> Result { + Self::deserialize_varint128(de) + } + #[inline(always)] + fn deserialize_i128<'de, R: BincodeRead<'de>, O: Options>( + de: &mut ::Deserializer, + ) -> Result { + Self::deserialize_varint128(de).map(Self::zigzag128_decode) + } + } +} + #[derive(Clone, Copy, Debug)] enum LimitOption { Unlimited, @@ -303,6 +841,12 @@ pub struct WithOtherEndian { _endian: PhantomData, } +/// A configuration struct with a user-specified length encoding +pub struct WithOtherIntEncoding { + options: O, + _length: PhantomData, +} + impl WithOtherLimit { #[inline(always)] pub(crate) fn new(options: O, limit: L) -> WithOtherLimit { @@ -323,9 +867,20 @@ impl WithOtherEndian { } } -impl Options for WithOtherEndian { +impl WithOtherIntEncoding { + #[inline(always)] + pub(crate) fn new(options: O) -> WithOtherIntEncoding { + WithOtherIntEncoding { + options, + _length: PhantomData, + } + } +} + +impl InternalOptions for WithOtherEndian { type Limit = O::Limit; type Endian = E; + type IntEncoding = O::IntEncoding; #[inline(always)] fn limit(&mut self) -> &mut O::Limit { @@ -333,15 +888,26 @@ impl Options for WithOtherEndian Options for WithOtherLimit { +impl InternalOptions for WithOtherLimit { type Limit = L; type Endian = O::Endian; + type IntEncoding = O::IntEncoding; fn limit(&mut self) -> &mut L { &mut self.new_limit } } +impl InternalOptions for WithOtherIntEncoding { + type Limit = O::Limit; + type Endian = O::Endian; + type IntEncoding = I; + + fn limit(&mut self) -> &mut O::Limit { + self.options.limit() + } +} + macro_rules! config_map { ($self:expr, $opts:ident => $call:expr) => { match ($self.limit, $self.endian) { @@ -531,16 +1097,18 @@ mod internal { use super::*; use byteorder::ByteOrder; - pub trait Options { + pub trait InternalOptions { type Limit: SizeLimit + 'static; type Endian: BincodeByteOrder + 'static; + type IntEncoding: IntEncoding + 'static; fn limit(&mut self) -> &mut Self::Limit; } - impl<'a, O: Options> Options for &'a mut O { + impl<'a, O: InternalOptions> InternalOptions for &'a mut O { type Limit = O::Limit; type Endian = O::Endian; + type IntEncoding = O::IntEncoding; #[inline(always)] fn limit(&mut self) -> &mut Self::Limit { @@ -560,4 +1128,152 @@ mod internal { pub trait BincodeByteOrder { type Endian: ByteOrder + 'static; } + + pub trait IntEncoding { + /// Gets the size (in bytes) that a value would be serialized to. + fn u16_size(n: u16) -> u64; + /// Gets the size (in bytes) that a value would be serialized to. + fn u32_size(n: u32) -> u64; + /// Gets the size (in bytes) that a value would be serialized to. + fn u64_size(n: u64) -> u64; + + /// Gets the size (in bytes) that a value would be serialized to. + fn i16_size(n: i16) -> u64; + /// Gets the size (in bytes) that a value would be serialized to. + fn i32_size(n: i32) -> u64; + /// Gets the size (in bytes) that a value would be serialized to. + fn i64_size(n: i64) -> u64; + + #[inline(always)] + fn len_size(len: usize) -> u64 { + Self::u64_size(len as u64) + } + + /// Serializes a sequence length. + #[inline(always)] + fn serialize_len( + ser: &mut ::ser::Serializer, + len: usize, + ) -> Result<()> { + Self::serialize_u64(ser, len as u64) + } + + fn serialize_u16( + ser: &mut ::ser::Serializer, + val: u16, + ) -> Result<()>; + + fn serialize_u32( + ser: &mut ::ser::Serializer, + val: u32, + ) -> Result<()>; + + fn serialize_u64( + ser: &mut ::ser::Serializer, + val: u64, + ) -> Result<()>; + + fn serialize_i16( + ser: &mut ::ser::Serializer, + val: i16, + ) -> Result<()>; + + fn serialize_i32( + ser: &mut ::ser::Serializer, + val: i32, + ) -> Result<()>; + + fn serialize_i64( + ser: &mut ::ser::Serializer, + val: i64, + ) -> Result<()>; + + /// Deserializes a sequence length. + #[inline(always)] + fn deserialize_len<'de, R: BincodeRead<'de>, O: Options>( + de: &mut ::de::Deserializer, + ) -> Result { + Self::deserialize_u64(de).and_then(cast_u64_to_usize) + } + + fn deserialize_u16<'de, R: BincodeRead<'de>, O: Options>( + de: &mut ::de::Deserializer, + ) -> Result; + + fn deserialize_u32<'de, R: BincodeRead<'de>, O: Options>( + de: &mut ::de::Deserializer, + ) -> Result; + + fn deserialize_u64<'de, R: BincodeRead<'de>, O: Options>( + de: &mut ::de::Deserializer, + ) -> Result; + + fn deserialize_i16<'de, R: BincodeRead<'de>, O: Options>( + de: &mut ::de::Deserializer, + ) -> Result; + + fn deserialize_i32<'de, R: BincodeRead<'de>, O: Options>( + de: &mut ::de::Deserializer, + ) -> Result; + + fn deserialize_i64<'de, R: BincodeRead<'de>, O: Options>( + de: &mut ::de::Deserializer, + ) -> Result; + + serde_if_integer128! { + fn u128_size(v: u128) -> u64; + fn i128_size(v: i128) -> u64; + fn serialize_u128( + ser: &mut ::Serializer, + val: u128, + ) -> Result<()>; + fn deserialize_u128<'de, R: BincodeRead<'de>, O: Options>( + de: &mut ::Deserializer, + ) -> Result; + fn serialize_i128( + ser: &mut ::Serializer, + val: i128, + ) -> Result<()>; + fn deserialize_i128<'de, R: BincodeRead<'de>, O: Options>( + de: &mut ::Deserializer, + ) -> Result; + } + } +} + +#[cfg(test)] +mod test { + use super::VarintEncoding; + + #[test] + fn test_zigzag_encode() { + let zigzag = VarintEncoding::zigzag_encode; + + assert_eq!(zigzag(0), 0); + for x in 1..512 { + assert_eq!(zigzag(x), (x as u64) * 2); + assert_eq!(zigzag(-x), (x as u64) * 2 - 1); + } + } + + #[test] + fn test_zigzag_decode() { + // zigzag' + let zigzagp = VarintEncoding::zigzag_decode; + for x in (0..512).map(|x| x * 2) { + assert_eq!(zigzagp(x), x as i64 / 2); + assert_eq!(zigzagp(x + 1), -(x as i64) / 2 - 1); + } + } + + #[test] + fn test_zigzag_edge_cases() { + let (zigzag, zigzagp) = (VarintEncoding::zigzag_encode, VarintEncoding::zigzag_decode); + + assert_eq!(zigzag(i64::max_value()), u64::max_value() - 1); + assert_eq!(zigzag(i64::min_value()), u64::max_value()); + + assert_eq!(zigzagp(u64::max_value() - 1), i64::max_value()); + assert_eq!(zigzagp(u64::max_value()), i64::min_value()); + } } diff --git a/src/de/mod.rs b/src/de/mod.rs index a38330c..080ea24 100644 --- a/src/de/mod.rs +++ b/src/de/mod.rs @@ -3,7 +3,7 @@ use std::io::Read; use self::read::{BincodeRead, IoReader, SliceReader}; use byteorder::ReadBytesExt; -use config::SizeLimit; +use config::{IntEncoding, SizeLimit}; use serde; use serde::de::Error as DeError; use serde::de::IntoDeserializer; @@ -30,6 +30,18 @@ pub struct Deserializer { options: O, } +macro_rules! impl_deserialize_literal { + ($name:ident : $ty:ty = $read:ident()) => { + #[inline] + pub(crate) fn $name(&mut self) -> Result<$ty> { + self.read_literal_type::<$ty>()?; + self.reader + .$read::<::Endian>() + .map_err(Into::into) + } + }; +} + impl<'de, R: BincodeRead<'de>, O: Options> Deserializer { /// Creates a new Deserializer with a given `Read`er and options. pub fn with_reader(r: IR, options: O) -> Deserializer, O> { @@ -52,17 +64,30 @@ impl<'de, R: BincodeRead<'de>, O: Options> Deserializer { Deserializer { reader: r, options } } + pub(crate) fn deserialize_byte(&mut self) -> Result { + self.read_literal_type::()?; + self.reader.read_u8().map_err(Into::into) + } + + impl_deserialize_literal! { deserialize_literal_u16 : u16 = read_u16() } + impl_deserialize_literal! { deserialize_literal_u32 : u32 = read_u32() } + impl_deserialize_literal! { deserialize_literal_u64 : u64 = read_u64() } + + serde_if_integer128! { + impl_deserialize_literal! { deserialize_literal_u128 : u128 = read_u128() } + } + fn read_bytes(&mut self, count: u64) -> Result<()> { self.options.limit().add(count) } - fn read_type(&mut self) -> Result<()> { + fn read_literal_type(&mut self) -> Result<()> { use std::mem::size_of; self.read_bytes(size_of::() as u64) } fn read_vec(&mut self) -> Result> { - let len: usize = serde::Deserialize::deserialize(&mut *self)?; + let len = O::IntEncoding::deserialize_len(self)?; self.read_bytes(len as u64)?; self.reader.get_byte_buffer(len) } @@ -73,17 +98,16 @@ impl<'de, R: BincodeRead<'de>, O: Options> Deserializer { } } -macro_rules! impl_nums { - ($ty:ty, $dser_method:ident, $visitor_method:ident, $reader_method:ident) => { +macro_rules! impl_deserialize_int { + ($name:ident = $visitor_method:ident ($dser_method:ident)) => { #[inline] - fn $dser_method(self, visitor: V) -> Result - where V: serde::de::Visitor<'de>, + fn $name(self, visitor: V) -> Result + where + V: serde::de::Visitor<'de>, { - self.read_type::<$ty>()?; - let value = self.reader.$reader_method::<::Endian>()?; - visitor.$visitor_method(value) + visitor.$visitor_method(O::IntEncoding::$dser_method(self)?) } - } + }; } impl<'de, 'a, R, O> serde::Deserializer<'de> for &'a mut Deserializer @@ -105,26 +129,45 @@ where where V: serde::de::Visitor<'de>, { - let value: u8 = serde::Deserialize::deserialize(self)?; - match value { + match self.deserialize_byte()? { 1 => visitor.visit_bool(true), 0 => visitor.visit_bool(false), value => Err(ErrorKind::InvalidBoolEncoding(value).into()), } } - impl_nums!(u16, deserialize_u16, visit_u16, read_u16); - impl_nums!(u32, deserialize_u32, visit_u32, read_u32); - impl_nums!(u64, deserialize_u64, visit_u64, read_u64); - impl_nums!(i16, deserialize_i16, visit_i16, read_i16); - impl_nums!(i32, deserialize_i32, visit_i32, read_i32); - impl_nums!(i64, deserialize_i64, visit_i64, read_i64); - impl_nums!(f32, deserialize_f32, visit_f32, read_f32); - impl_nums!(f64, deserialize_f64, visit_f64, read_f64); + impl_deserialize_int!(deserialize_u16 = visit_u16(deserialize_u16)); + impl_deserialize_int!(deserialize_u32 = visit_u32(deserialize_u32)); + impl_deserialize_int!(deserialize_u64 = visit_u64(deserialize_u64)); + impl_deserialize_int!(deserialize_i16 = visit_i16(deserialize_i16)); + impl_deserialize_int!(deserialize_i32 = visit_i32(deserialize_i32)); + impl_deserialize_int!(deserialize_i64 = visit_i64(deserialize_i64)); + + fn deserialize_f32(self, visitor: V) -> Result + where + V: serde::de::Visitor<'de>, + { + self.read_literal_type::()?; + let value = self + .reader + .read_f32::<::Endian>()?; + visitor.visit_f32(value) + } + + fn deserialize_f64(self, visitor: V) -> Result + where + V: serde::de::Visitor<'de>, + { + self.read_literal_type::()?; + let value = self + .reader + .read_f64::<::Endian>()?; + visitor.visit_f64(value) + } serde_if_integer128! { - impl_nums!(u128, deserialize_u128, visit_u128, read_u128); - impl_nums!(i128, deserialize_i128, visit_i128, read_i128); + impl_deserialize_int!(deserialize_u128 = visit_u128(deserialize_u128)); + impl_deserialize_int!(deserialize_i128 = visit_i128(deserialize_i128)); } #[inline] @@ -132,8 +175,7 @@ where where V: serde::de::Visitor<'de>, { - self.read_type::()?; - visitor.visit_u8(self.reader.read_u8()?) + visitor.visit_u8(self.deserialize_byte()? as u8) } #[inline] @@ -141,8 +183,7 @@ where where V: serde::de::Visitor<'de>, { - self.read_type::()?; - visitor.visit_i8(self.reader.read_i8()?) + visitor.visit_i8(self.deserialize_byte()? as i8) } fn deserialize_unit(self, visitor: V) -> Result @@ -187,7 +228,7 @@ where where V: serde::de::Visitor<'de>, { - let len: usize = serde::Deserialize::deserialize(&mut *self)?; + let len = O::IntEncoding::deserialize_len(self)?; self.read_bytes(len as u64)?; self.reader.forward_read_str(len, visitor) } @@ -203,7 +244,7 @@ where where V: serde::de::Visitor<'de>, { - let len: usize = serde::Deserialize::deserialize(&mut *self)?; + let len = O::IntEncoding::deserialize_len(self)?; self.read_bytes(len as u64)?; self.reader.forward_read_bytes(len, visitor) } @@ -236,7 +277,7 @@ where where V: serde::de::DeserializeSeed<'de>, { - let idx: u32 = serde::de::Deserialize::deserialize(&mut *self)?; + let idx: u32 = O::IntEncoding::deserialize_u32(self)?; let val: Result<_> = seed.deserialize(idx.into_deserializer()); Ok((val?, self)) } @@ -300,7 +341,7 @@ where where V: serde::de::Visitor<'de>, { - let len = serde::Deserialize::deserialize(&mut *self)?; + let len = O::IntEncoding::deserialize_len(self)?; self.deserialize_tuple(len, visitor) } @@ -346,7 +387,7 @@ where } } - let len = serde::Deserialize::deserialize(&mut *self)?; + let len = O::IntEncoding::deserialize_len(self)?; visitor.visit_map(Access { deserializer: self, diff --git a/src/internal.rs b/src/internal.rs index f38eab9..be13d31 100644 --- a/src/internal.rs +++ b/src/internal.rs @@ -2,7 +2,7 @@ use serde; use std::io::{Read, Write}; use std::marker::PhantomData; -use config::{Infinite, Options, OptionsExt, SizeLimit}; +use config::{Infinite, InternalOptions, Options, SizeLimit}; use de::read::BincodeRead; use Result; @@ -10,7 +10,7 @@ pub(crate) fn serialize_into(writer: W, value: &T, mut options: where W: Write, T: serde::Serialize, - O: Options, + O: InternalOptions, { if options.limit().limit().is_some() { // "compute" the size for the side-effect @@ -25,7 +25,7 @@ where pub(crate) fn serialize(value: &T, mut options: O) -> Result> where T: serde::Serialize, - O: Options, + O: InternalOptions, { let mut writer = { let actual_size = serialized_size(value, &mut options)?; @@ -36,7 +36,7 @@ where Ok(writer) } -pub(crate) fn serialized_size(value: &T, options: O) -> Result +pub(crate) fn serialized_size(value: &T, options: O) -> Result where T: serde::Serialize, { @@ -50,7 +50,7 @@ pub(crate) fn deserialize_from(reader: R, options: O) -> Result where R: Read, T: serde::de::DeserializeOwned, - O: Options, + O: InternalOptions, { deserialize_from_seed(PhantomData, reader, options) } @@ -59,7 +59,7 @@ pub(crate) fn deserialize_from_seed<'a, R, T, O>(seed: T, reader: R, options: O) where R: Read, T: serde::de::DeserializeSeed<'a>, - O: Options, + O: InternalOptions, { let reader = ::de::read::IoReader::new(reader); deserialize_from_custom_seed(seed, reader, options) @@ -69,7 +69,7 @@ pub(crate) fn deserialize_from_custom<'a, R, T, O>(reader: R, options: O) -> Res where R: BincodeRead<'a>, T: serde::de::DeserializeOwned, - O: Options, + O: InternalOptions, { deserialize_from_custom_seed(PhantomData, reader, options) } @@ -82,7 +82,7 @@ pub(crate) fn deserialize_from_custom_seed<'a, R, T, O>( where R: BincodeRead<'a>, T: serde::de::DeserializeSeed<'a>, - O: Options, + O: InternalOptions, { let mut deserializer = ::de::Deserializer::<_, O>::with_bincode_read(reader, options); seed.deserialize(&mut deserializer) @@ -92,7 +92,7 @@ pub(crate) fn deserialize_in_place<'a, R, T, O>(reader: R, options: O, place: &m where R: BincodeRead<'a>, T: serde::de::Deserialize<'a>, - O: Options, + O: InternalOptions, { let mut deserializer = ::de::Deserializer::<_, _>::with_bincode_read(reader, options); serde::Deserialize::deserialize_in_place(&mut deserializer, place) @@ -101,7 +101,7 @@ where pub(crate) fn deserialize<'a, T, O>(bytes: &'a [u8], options: O) -> Result where T: serde::de::Deserialize<'a>, - O: Options, + O: InternalOptions, { deserialize_seed(PhantomData, bytes, options) } @@ -109,7 +109,7 @@ where pub(crate) fn deserialize_seed<'a, T, O>(seed: T, bytes: &'a [u8], options: O) -> Result where T: serde::de::DeserializeSeed<'a>, - O: Options, + O: InternalOptions, { let reader = ::de::read::SliceReader::new(bytes); let options = ::config::WithOtherLimit::new(options, Infinite); diff --git a/src/lib.rs b/src/lib.rs index 668314b..d6e2160 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -42,7 +42,7 @@ mod error; mod internal; mod ser; -pub use config::{Config, DefaultOptions, OptionsExt}; +pub use config::{Config, DefaultOptions, Options}; pub use de::read::BincodeRead; pub use de::Deserializer; pub use error::{Error, ErrorKind, Result}; diff --git a/src/ser/mod.rs b/src/ser/mod.rs index 442e34b..033d870 100644 --- a/src/ser/mod.rs +++ b/src/ser/mod.rs @@ -5,9 +5,10 @@ use serde; use byteorder::WriteBytesExt; -use super::config::SizeLimit; +use super::config::{IntEncoding, SizeLimit}; use super::{Error, ErrorKind, Result}; use config::{BincodeByteOrder, Options}; +use std::mem::size_of; /// An Serializer that encodes values directly into a Writer. /// @@ -21,6 +22,16 @@ pub struct Serializer { _options: O, } +macro_rules! impl_serialize_literal { + ($ser_method:ident($ty:ty) = $write:ident()) => { + pub(crate) fn $ser_method(&mut self, v: $ty) -> Result<()> { + self.writer + .$write::<::Endian>(v) + .map_err(Into::into) + } + }; +} + impl Serializer { /// Creates a new Serializer with the given `Write`r. pub fn new(w: W, options: O) -> Serializer { @@ -29,6 +40,26 @@ impl Serializer { _options: options, } } + + pub(crate) fn serialize_byte(&mut self, v: u8) -> Result<()> { + self.writer.write_u8(v).map_err(Into::into) + } + + impl_serialize_literal! {serialize_literal_u16(u16) = write_u16()} + impl_serialize_literal! {serialize_literal_u32(u32) = write_u32()} + impl_serialize_literal! {serialize_literal_u64(u64) = write_u64()} + + serde_if_integer128! { + impl_serialize_literal!{serialize_literal_u128(u128) = write_u128()} + } +} + +macro_rules! impl_serialize_int { + ($ser_method:ident($ty:ty) = $ser_int:ident()) => { + fn $ser_method(self, v: $ty) -> Result<()> { + O::IntEncoding::$ser_int(self, v) + } + }; } impl<'a, W: Write, O: Options> serde::Serializer for &'a mut Serializer { @@ -51,79 +82,44 @@ impl<'a, W: Write, O: Options> serde::Serializer for &'a mut Serializer { } fn serialize_bool(self, v: bool) -> Result<()> { - self.writer - .write_u8(if v { 1 } else { 0 }) - .map_err(Into::into) + self.serialize_byte(v as u8) } fn serialize_u8(self, v: u8) -> Result<()> { - self.writer.write_u8(v).map_err(Into::into) + self.serialize_byte(v) } - fn serialize_u16(self, v: u16) -> Result<()> { - self.writer - .write_u16::<::Endian>(v) - .map_err(Into::into) - } - - fn serialize_u32(self, v: u32) -> Result<()> { - self.writer - .write_u32::<::Endian>(v) - .map_err(Into::into) - } - - fn serialize_u64(self, v: u64) -> Result<()> { - self.writer - .write_u64::<::Endian>(v) - .map_err(Into::into) - } + impl_serialize_int! {serialize_u16(u16) = serialize_u16()} + impl_serialize_int! {serialize_u32(u32) = serialize_u32()} + impl_serialize_int! {serialize_u64(u64) = serialize_u64()} fn serialize_i8(self, v: i8) -> Result<()> { - self.writer.write_i8(v).map_err(Into::into) + self.serialize_byte(v as u8) } - fn serialize_i16(self, v: i16) -> Result<()> { - self.writer - .write_i16::<::Endian>(v) - .map_err(Into::into) - } - - fn serialize_i32(self, v: i32) -> Result<()> { - self.writer - .write_i32::<::Endian>(v) - .map_err(Into::into) - } - - fn serialize_i64(self, v: i64) -> Result<()> { - self.writer - .write_i64::<::Endian>(v) - .map_err(Into::into) - } + impl_serialize_int! {serialize_i16(i16) = serialize_i16()} + impl_serialize_int! {serialize_i32(i32) = serialize_i32()} + impl_serialize_int! {serialize_i64(i64) = serialize_i64()} serde_if_integer128! { - fn serialize_u128(self, v: u128) -> Result<()> { - self.writer.write_u128::<::Endian>(v).map_err(Into::into) - } - - fn serialize_i128(self, v: i128) -> Result<()> { - self.writer.write_i128::<::Endian>(v).map_err(Into::into) - } + impl_serialize_int!{serialize_u128(u128) = serialize_u128()} + impl_serialize_int!{serialize_i128(i128) = serialize_i128()} } fn serialize_f32(self, v: f32) -> Result<()> { self.writer - .write_f32::<<::Endian as BincodeByteOrder>::Endian>(v) + .write_f32::<::Endian>(v) .map_err(Into::into) } fn serialize_f64(self, v: f64) -> Result<()> { self.writer - .write_f64::<<::Endian as BincodeByteOrder>::Endian>(v) + .write_f64::<::Endian>(v) .map_err(Into::into) } fn serialize_str(self, v: &str) -> Result<()> { - self.serialize_u64(v.len() as u64)?; + O::IntEncoding::serialize_len(self, v.len())?; self.writer.write_all(v.as_bytes()).map_err(Into::into) } @@ -134,7 +130,7 @@ impl<'a, W: Write, O: Options> serde::Serializer for &'a mut Serializer { } fn serialize_bytes(self, v: &[u8]) -> Result<()> { - self.serialize_u64(v.len() as u64)?; + O::IntEncoding::serialize_len(self, v.len())?; self.writer.write_all(v).map_err(Into::into) } @@ -152,7 +148,7 @@ impl<'a, W: Write, O: Options> serde::Serializer for &'a mut Serializer { fn serialize_seq(self, len: Option) -> Result { let len = len.ok_or(ErrorKind::SequenceMustHaveLength)?; - self.serialize_u64(len as u64)?; + O::IntEncoding::serialize_len(self, len)?; Ok(Compound { ser: self }) } @@ -175,13 +171,13 @@ impl<'a, W: Write, O: Options> serde::Serializer for &'a mut Serializer { _variant: &'static str, _len: usize, ) -> Result { - self.serialize_u32(variant_index)?; + O::IntEncoding::serialize_u32(self, variant_index)?; Ok(Compound { ser: self }) } fn serialize_map(self, len: Option) -> Result { let len = len.ok_or(ErrorKind::SequenceMustHaveLength)?; - self.serialize_u64(len as u64)?; + O::IntEncoding::serialize_len(self, len)?; Ok(Compound { ser: self }) } @@ -196,7 +192,7 @@ impl<'a, W: Write, O: Options> serde::Serializer for &'a mut Serializer { _variant: &'static str, _len: usize, ) -> Result { - self.serialize_u32(variant_index)?; + O::IntEncoding::serialize_u32(self, variant_index)?; Ok(Compound { ser: self }) } @@ -217,7 +213,7 @@ impl<'a, W: Write, O: Options> serde::Serializer for &'a mut Serializer { where T: serde::ser::Serialize, { - self.serialize_u32(variant_index)?; + O::IntEncoding::serialize_u32(self, variant_index)?; value.serialize(self) } @@ -227,7 +223,7 @@ impl<'a, W: Write, O: Options> serde::Serializer for &'a mut Serializer { variant_index: u32, _variant: &'static str, ) -> Result<()> { - self.serialize_u32(variant_index) + O::IntEncoding::serialize_u32(self, variant_index) } fn is_human_readable(&self) -> bool { @@ -248,10 +244,23 @@ impl SizeChecker { Ok(()) } - fn add_value(&mut self, t: T) -> Result<()> { - use std::mem::size_of_val; - self.add_raw(size_of_val(&t) as u64) + fn add_discriminant(&mut self, idx: u32) -> Result<()> { + let bytes = O::IntEncoding::u32_size(idx); + self.add_raw(bytes) } + + fn add_len(&mut self, len: usize) -> Result<()> { + let bytes = O::IntEncoding::len_size(len); + self.add_raw(bytes) + } +} + +macro_rules! impl_size_int { + ($ser_method:ident($ty:ty) = $size_method:ident()) => { + fn $ser_method(self, v: $ty) -> Result<()> { + self.add_raw(O::IntEncoding::$size_method(v)) + } + }; } impl<'a, O: Options> serde::Serializer for &'a mut SizeChecker { @@ -274,61 +283,38 @@ impl<'a, O: Options> serde::Serializer for &'a mut SizeChecker { } fn serialize_bool(self, _: bool) -> Result<()> { - self.add_value(0 as u8) + self.add_raw(1) } - fn serialize_u8(self, v: u8) -> Result<()> { - self.add_value(v) + fn serialize_u8(self, _: u8) -> Result<()> { + self.add_raw(1) + } + fn serialize_i8(self, _: i8) -> Result<()> { + self.add_raw(1) } - fn serialize_u16(self, v: u16) -> Result<()> { - self.add_value(v) - } - - fn serialize_u32(self, v: u32) -> Result<()> { - self.add_value(v) - } - - fn serialize_u64(self, v: u64) -> Result<()> { - self.add_value(v) - } - - fn serialize_i8(self, v: i8) -> Result<()> { - self.add_value(v) - } - - fn serialize_i16(self, v: i16) -> Result<()> { - self.add_value(v) - } - - fn serialize_i32(self, v: i32) -> Result<()> { - self.add_value(v) - } - - fn serialize_i64(self, v: i64) -> Result<()> { - self.add_value(v) - } + impl_size_int! {serialize_u16(u16) = u16_size()} + impl_size_int! {serialize_u32(u32) = u32_size()} + impl_size_int! {serialize_u64(u64) = u64_size()} + impl_size_int! {serialize_i16(i16) = i16_size()} + impl_size_int! {serialize_i32(i32) = i32_size()} + impl_size_int! {serialize_i64(i64) = i64_size()} serde_if_integer128! { - fn serialize_u128(self, v: u128) -> Result<()> { - self.add_value(v) - } - - fn serialize_i128(self, v: i128) -> Result<()> { - self.add_value(v) - } + impl_size_int!{serialize_u128(u128) = u128_size()} + impl_size_int!{serialize_i128(i128) = i128_size()} } - fn serialize_f32(self, v: f32) -> Result<()> { - self.add_value(v) + fn serialize_f32(self, _: f32) -> Result<()> { + self.add_raw(size_of::() as u64) } - fn serialize_f64(self, v: f64) -> Result<()> { - self.add_value(v) + fn serialize_f64(self, _: f64) -> Result<()> { + self.add_raw(size_of::() as u64) } fn serialize_str(self, v: &str) -> Result<()> { - self.add_value(0 as u64)?; + self.add_len(v.len())?; self.add_raw(v.len() as u64) } @@ -337,26 +323,26 @@ impl<'a, O: Options> serde::Serializer for &'a mut SizeChecker { } fn serialize_bytes(self, v: &[u8]) -> Result<()> { - self.add_value(0 as u64)?; + self.add_len(v.len())?; self.add_raw(v.len() as u64) } fn serialize_none(self) -> Result<()> { - self.add_value(0 as u8) + self.add_raw(1) } fn serialize_some(self, v: &T) -> Result<()> where T: serde::Serialize, { - self.add_value(1 as u8)?; + self.add_raw(1)?; v.serialize(self) } fn serialize_seq(self, len: Option) -> Result { let len = len.ok_or(ErrorKind::SequenceMustHaveLength)?; - self.serialize_u64(len as u64)?; + self.add_len(len)?; Ok(SizeCompound { ser: self }) } @@ -379,14 +365,14 @@ impl<'a, O: Options> serde::Serializer for &'a mut SizeChecker { _variant: &'static str, _len: usize, ) -> Result { - self.add_value(variant_index)?; + self.add_raw(O::IntEncoding::u32_size(variant_index))?; Ok(SizeCompound { ser: self }) } fn serialize_map(self, len: Option) -> Result { let len = len.ok_or(ErrorKind::SequenceMustHaveLength)?; - self.serialize_u64(len as u64)?; + self.add_len(len)?; Ok(SizeCompound { ser: self }) } @@ -401,7 +387,7 @@ impl<'a, O: Options> serde::Serializer for &'a mut SizeChecker { _variant: &'static str, _len: usize, ) -> Result { - self.add_value(variant_index)?; + self.add_discriminant(variant_index)?; Ok(SizeCompound { ser: self }) } @@ -419,7 +405,7 @@ impl<'a, O: Options> serde::Serializer for &'a mut SizeChecker { variant_index: u32, _variant: &'static str, ) -> Result<()> { - self.add_value(variant_index) + self.add_discriminant(variant_index) } fn serialize_newtype_variant( @@ -429,7 +415,7 @@ impl<'a, O: Options> serde::Serializer for &'a mut SizeChecker { _variant: &'static str, value: &V, ) -> Result<()> { - self.add_value(variant_index)?; + self.add_discriminant(variant_index)?; value.serialize(self) } diff --git a/tests/test.rs b/tests/test.rs index 201ed47..9797079 100644 --- a/tests/test.rs +++ b/tests/test.rs @@ -14,43 +14,53 @@ use std::result::Result as StdResult; use bincode::{ deserialize, deserialize_from, deserialize_in_place, serialize, serialized_size, - DefaultOptions, ErrorKind, OptionsExt, Result, + DefaultOptions, ErrorKind, Options, Result, }; use serde::de::{Deserialize, DeserializeSeed, Deserializer, SeqAccess, Visitor}; -fn the_same(element: V) +const LEN_SIZE: u64 = 8; + +fn the_same_impl(element: V, options: &mut O) where V: serde::Serialize + serde::de::DeserializeOwned + PartialEq + Debug + 'static, + O: Options, { - let size = serialized_size(&element).unwrap(); + let size = options.serialized_size(&element).unwrap(); { - let encoded = serialize(&element).unwrap(); - let decoded = deserialize(&encoded[..]).unwrap(); - - assert_eq!(element, decoded); - assert_eq!(size, encoded.len() as u64); - } - - { - let encoded = DefaultOptions::new() - .with_big_endian() - .serialize(&element) - .unwrap(); - let decoded = DefaultOptions::new() - .with_big_endian() - .deserialize(&encoded[..]) - .unwrap(); - let decoded_reader = DefaultOptions::new() - .with_big_endian() - .deserialize_from(&mut &encoded[..]) - .unwrap(); + let encoded = options.serialize(&element).unwrap(); + let decoded: V = options.deserialize(&encoded[..]).unwrap(); + let decoded_reader = options.deserialize_from(&mut &encoded[..]).unwrap(); assert_eq!(element, decoded); assert_eq!(element, decoded_reader); assert_eq!(size, encoded.len() as u64); } } + +fn the_same(element: V) +where + V: serde::Serialize + serde::de::DeserializeOwned + PartialEq + Debug + Clone + 'static, +{ + // add a new macro which calls the previous when you add a new option set + macro_rules! all_endians { + ($element:expr, $options:expr) => { + the_same_impl($element.clone(), &mut $options.with_native_endian()); + the_same_impl($element.clone(), &mut $options.with_big_endian()); + the_same_impl($element.clone(), &mut $options.with_little_endian()); + }; + } + + macro_rules! all_integer_encodings { + ($element:expr, $options:expr) => { + all_endians!($element, $options.with_fixint_encoding()); + all_endians!($element, $options.with_varint_encoding()); + }; + } + + all_integer_encodings!(element, DefaultOptions::new()); +} + #[test] fn test_numbers() { // unsigned positive @@ -109,7 +119,7 @@ fn test_tuple() { #[test] fn test_basic_struct() { - #[derive(Serialize, Deserialize, PartialEq, Debug)] + #[derive(Serialize, Deserialize, PartialEq, Debug, Clone)] struct Easy { x: isize, s: String, @@ -124,13 +134,13 @@ fn test_basic_struct() { #[test] fn test_nested_struct() { - #[derive(Serialize, Deserialize, PartialEq, Debug)] + #[derive(Serialize, Deserialize, PartialEq, Debug, Clone)] struct Easy { x: isize, s: String, y: usize, } - #[derive(Serialize, Deserialize, PartialEq, Debug)] + #[derive(Serialize, Deserialize, PartialEq, Debug, Clone)] struct Nest { f: Easy, b: usize, @@ -154,7 +164,7 @@ fn test_nested_struct() { #[test] fn test_struct_newtype() { - #[derive(Serialize, Deserialize, PartialEq, Debug)] + #[derive(Serialize, Deserialize, PartialEq, Debug, Clone)] struct NewtypeStr(usize); the_same(NewtypeStr(5)); @@ -162,7 +172,7 @@ fn test_struct_newtype() { #[test] fn test_struct_tuple() { - #[derive(Serialize, Deserialize, PartialEq, Debug)] + #[derive(Serialize, Deserialize, PartialEq, Debug, Clone)] struct TubStr(usize, String, f32); the_same(TubStr(5, "hello".to_string(), 3.2)); @@ -177,7 +187,7 @@ fn test_option() { #[test] fn test_enum() { - #[derive(Serialize, Deserialize, PartialEq, Debug)] + #[derive(Serialize, Deserialize, PartialEq, Debug, Clone)] enum TestEnum { NoArg, OneArg(usize), @@ -239,7 +249,10 @@ fn deserializing_errors() { ErrorKind::InvalidBoolEncoding(0xA) => {} _ => panic!(), } - match *deserialize::(&vec![1, 0, 0, 0, 0, 0, 0, 0, 0xFF][..]).unwrap_err() { + + let invalid_str = vec![1, 0, 0, 0, 0, 0, 0, 0, 0xFF]; + + match *deserialize::(&invalid_str[..]).unwrap_err() { ErrorKind::InvalidUtf8Encoding(_) => {} _ => panic!(), } @@ -251,7 +264,9 @@ fn deserializing_errors() { Two, }; - match *deserialize::(&vec![0, 0, 0, 5][..]).unwrap_err() { + let invalid_enum = vec![0, 0, 0, 5]; + + match *deserialize::(&invalid_enum[..]).unwrap_err() { // Error message comes from serde ErrorKind::Custom(_) => {} _ => panic!(), @@ -309,11 +324,11 @@ fn too_big_serialize() { assert!(DefaultOptions::new().with_limit(4).serialize(&0u32).is_ok()); assert!(DefaultOptions::new() - .with_limit(8 + 4) + .with_limit(LEN_SIZE + 4) .serialize(&"abcde") .is_err()); assert!(DefaultOptions::new() - .with_limit(8 + 5) + .with_limit(LEN_SIZE + 5) .serialize(&"abcde") .is_ok()); } @@ -326,10 +341,10 @@ fn test_serialized_size() { assert!(serialized_size(&0u64).unwrap() == 8); // length isize stored as u64 - assert!(serialized_size(&"").unwrap() == 8); - assert!(serialized_size(&"a").unwrap() == 8 + 1); + assert!(serialized_size(&"").unwrap() == LEN_SIZE); + assert!(serialized_size(&"a").unwrap() == LEN_SIZE + 1); - assert!(serialized_size(&vec![0u32, 1u32, 2u32]).unwrap() == 8 + 3 * (4)); + assert!(serialized_size(&vec![0u32, 1u32, 2u32]).unwrap() == LEN_SIZE + 3 * (4)); } #[test] @@ -368,21 +383,21 @@ fn test_serialized_size_bounded() { .with_limit(8) .serialized_size(&"") .unwrap() - == 8 + == LEN_SIZE ); assert!( DefaultOptions::new() .with_limit(8 + 1) .serialized_size(&"a") .unwrap() - == 8 + 1 + == LEN_SIZE + 1 ); assert!( DefaultOptions::new() - .with_limit(8 + 3 * 4) + .with_limit(LEN_SIZE + 3 * 4) .serialized_size(&vec![0u32, 1u32, 2u32]) .unwrap() - == 8 + 3 * 4 + == LEN_SIZE + 3 * 4 ); // Below assert!(DefaultOptions::new() @@ -794,3 +809,40 @@ fn test_big_endian_deserialize_from_seed() { assert_eq!(seed_data, (0..100).collect::>()); } + +#[test] +fn test_varint_length_prefixes() { + let a = vec![(); 127]; // should be a single byte + let b = vec![(); 250]; // also should be a single byte + let c = vec![(); 251]; + let d = vec![(); u16::max_value() as usize + 1]; + + assert_eq!( + DefaultOptions::new() + .with_varint_encoding() + .serialized_size(&a[..]) + .unwrap(), + 1 + ); // 2 ** 7 - 1 + assert_eq!( + DefaultOptions::new() + .with_varint_encoding() + .serialized_size(&b[..]) + .unwrap(), + 1 + ); // 250 + assert_eq!( + DefaultOptions::new() + .with_varint_encoding() + .serialized_size(&c[..]) + .unwrap(), + (1 + std::mem::size_of::()) as u64 + ); // 251 + assert_eq!( + DefaultOptions::new() + .with_varint_encoding() + .serialized_size(&d[..]) + .unwrap(), + (1 + std::mem::size_of::()) as u64 + ); // 2 ** 16 + 1 +}