From 2355e48a7bf05bf17fdfb729ed46d35cada475b8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lena=20Hellstr=C3=B6m?= Date: Thu, 16 Apr 2020 15:23:07 -0700 Subject: [PATCH] expose default options and serializers (#310) Deprecate the old config system and make a refined version of the internal config system public. Doing allows the Serializer/Deserializer to be exposed since all of its generic type parameters are now public. --- src/config.rs | 349 +++++++++++++++++++++++++++++++++++++----------- src/de/mod.rs | 31 ++++- src/de/read.rs | 10 +- src/internal.rs | 88 +----------- src/lib.rs | 78 +++-------- src/ser/mod.rs | 50 ++++--- tests/test.rs | 160 ++++++++++++++++------ 7 files changed, 478 insertions(+), 288 deletions(-) diff --git a/src/config.rs b/src/config.rs index d8ca050..eeeae5a 100644 --- a/src/config.rs +++ b/src/config.rs @@ -1,64 +1,43 @@ -use super::internal::{Bounded, Infinite, SizeLimit}; -use byteorder::{BigEndian, ByteOrder, LittleEndian, NativeEndian}; +use byteorder; use de::read::BincodeRead; -use error::Result; +use error::{ErrorKind, Result}; use serde; use std::io::{Read, Write}; use std::marker::PhantomData; -use {DeserializerAcceptor, SerializerAcceptor}; + +pub(crate) use self::internal::*; use self::EndianOption::*; use self::LimitOption::*; -struct DefaultOptions(Infinite); - -pub(crate) trait Options { - type Limit: SizeLimit + 'static; - type Endian: ByteOrder + 'static; - - fn limit(&mut self) -> &mut Self::Limit; -} - -pub(crate) trait OptionsExt: Options + Sized { - fn with_no_limit(self) -> WithOtherLimit { - WithOtherLimit::new(self, Infinite) - } - - fn with_limit(self, limit: u64) -> WithOtherLimit { - WithOtherLimit::new(self, Bounded(limit)) - } - - fn with_little_endian(self) -> WithOtherEndian { - WithOtherEndian::new(self) - } - - fn with_big_endian(self) -> WithOtherEndian { - WithOtherEndian::new(self) - } - - fn with_native_endian(self) -> WithOtherEndian { - WithOtherEndian::new(self) - } -} - -impl<'a, O: Options> Options for &'a mut O { - type Limit = O::Limit; - type Endian = O::Endian; - - #[inline(always)] - fn limit(&mut self) -> &mut Self::Limit { - (*self).limit() - } -} - -impl OptionsExt for T {} +/// 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 +/// limit the number of serialized/deserialized bytes. +#[derive(Copy, Clone)] +pub struct DefaultOptions(Infinite); impl DefaultOptions { - fn new() -> DefaultOptions { + /// Get a default configuration object. + /// + /// ### Default Configuration: + /// + /// | Byte limit | Endianness | + /// |------------|------------| + /// | Unlimited | Little | + pub fn new() -> DefaultOptions { DefaultOptions(Infinite) } } +impl Default for DefaultOptions { + fn default() -> Self { + Self::new() + } +} + impl Options for DefaultOptions { type Limit = Infinite; type Endian = LittleEndian; @@ -69,6 +48,211 @@ impl Options for DefaultOptions { } } +/// A configuration builder trait whose options Bincode will use +/// while serializing and deserializing. +/// +/// ### Options +/// Endianness: The endianness with which multi-byte integers will be read/written. *default: little endian* +/// +/// Limit: The maximum number of bytes that will be read/written in a bincode serialize/deserialize. *default: unlimited* +/// +/// ### Byte Limit Details +/// The purpose of byte-limiting is to prevent Denial-Of-Service attacks whereby malicious attackers get bincode +/// deserialization to crash your process by allocating too much memory or keeping a connection open for too long. +/// +/// 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. +/// Sets the byte limit to be unlimited. +/// This is the default. +pub trait OptionsExt: Options + Sized { + /// Sets the byte limit to be unlimited. + /// This is the default. + fn with_no_limit(self) -> WithOtherLimit { + WithOtherLimit::new(self, Infinite) + } + + /// Sets the byte limit to `limit`. + fn with_limit(self, limit: u64) -> WithOtherLimit { + WithOtherLimit::new(self, Bounded(limit)) + } + + /// Sets the endianness to little-endian + /// This is the default. + fn with_little_endian(self) -> WithOtherEndian { + WithOtherEndian::new(self) + } + + /// Sets the endianness to big-endian + fn with_big_endian(self) -> WithOtherEndian { + WithOtherEndian::new(self) + } + + /// Sets the endianness to the the machine-native endianness + fn with_native_endian(self) -> WithOtherEndian { + WithOtherEndian::new(self) + } + + /// Serializes a serializable object into a `Vec` of bytes using this configuration + #[inline(always)] + fn serialize(self, t: &S) -> Result> { + ::internal::serialize(t, self) + } + + /// Returns the size that an object would be if serialized using Bincode with this configuration + #[inline(always)] + fn serialized_size(self, t: &T) -> Result { + ::internal::serialized_size(t, self) + } + + /// Serializes an object directly into a `Writer` using this configuration + /// + /// If the serialization would take more bytes than allowed by the size limit, an error + /// is returned and *no bytes* will be written into the `Writer` + #[inline(always)] + fn serialize_into(self, w: W, t: &T) -> Result<()> { + ::internal::serialize_into(w, t, self) + } + + /// Deserializes a slice of bytes into an instance of `T` using this configuration + #[inline(always)] + fn deserialize<'a, T: serde::Deserialize<'a>>(self, bytes: &'a [u8]) -> Result { + ::internal::deserialize(bytes, self) + } + + /// TODO: document + #[doc(hidden)] + #[inline(always)] + fn deserialize_in_place<'a, R, T>(self, reader: R, place: &mut T) -> Result<()> + where + R: BincodeRead<'a>, + T: serde::de::Deserialize<'a>, + { + ::internal::deserialize_in_place(reader, self, place) + } + + /// Deserializes a slice of bytes with state `seed` using this configuration. + #[inline(always)] + fn deserialize_seed<'a, T: serde::de::DeserializeSeed<'a>>( + self, + seed: T, + bytes: &'a [u8], + ) -> Result { + ::internal::deserialize_seed(seed, bytes, self) + } + + /// Deserializes an object directly from a `Read`er using this configuration + /// + /// If this returns an `Error`, `reader` may be in an invalid state. + #[inline(always)] + fn deserialize_from(self, reader: R) -> Result { + ::internal::deserialize_from(reader, self) + } + + /// Deserializes an object directly from a `Read`er with state `seed` using this configuration + /// + /// If this returns an `Error`, `reader` may be in an invalid state. + #[inline(always)] + fn deserialize_from_seed<'a, R: Read, T: serde::de::DeserializeSeed<'a>>( + self, + seed: T, + reader: R, + ) -> Result { + ::internal::deserialize_from_seed(seed, reader, self) + } + + /// Deserializes an object from a custom `BincodeRead`er using the default configuration. + /// It is highly recommended to use `deserialize_from` unless you need to implement + /// `BincodeRead` for performance reasons. + /// + /// If this returns an `Error`, `reader` may be in an invalid state. + #[inline(always)] + fn deserialize_from_custom<'a, R: BincodeRead<'a>, T: serde::de::DeserializeOwned>( + self, + reader: R, + ) -> Result { + ::internal::deserialize_from_custom(reader, self) + } + + /// Deserializes an object from a custom `BincodeRead`er with state `seed` using the default + /// configuration. It is highly recommended to use `deserialize_from` unless you need to + /// implement `BincodeRead` for performance reasons. + /// + /// If this returns an `Error`, `reader` may be in an invalid state. + #[inline(always)] + fn deserialize_from_custom_seed<'a, R: BincodeRead<'a>, T: serde::de::DeserializeSeed<'a>>( + self, + seed: T, + reader: R, + ) -> Result { + ::internal::deserialize_from_custom_seed(seed, reader, self) + } +} + +impl OptionsExt for T {} + +/// A SizeLimit that restricts serialized or deserialized messages from +/// exceeding a certain byte length. +#[derive(Copy, Clone)] +pub struct Bounded(pub u64); + +/// A SizeLimit without a limit! +/// Use this if you don't care about the size of encoded or decoded messages. +#[derive(Copy, Clone)] +pub struct Infinite; + +impl SizeLimit for Bounded { + #[inline(always)] + fn add(&mut self, n: u64) -> Result<()> { + if self.0 >= n { + self.0 -= n; + Ok(()) + } else { + Err(Box::new(ErrorKind::SizeLimit)) + } + } + + #[inline(always)] + fn limit(&self) -> Option { + Some(self.0) + } +} + +impl SizeLimit for Infinite { + #[inline(always)] + fn add(&mut self, _: u64) -> Result<()> { + Ok(()) + } + + #[inline(always)] + fn limit(&self) -> Option { + None + } +} + +/// Little-endian byte ordering. +#[derive(Copy, Clone)] +pub struct LittleEndian; + +/// Big-endian byte ordering. +#[derive(Copy, Clone)] +pub struct BigEndian; + +/// The native byte ordering of the current system. +#[derive(Copy, Clone)] +pub struct NativeEndian; + +impl BincodeByteOrder for LittleEndian { + type Endian = byteorder::LittleEndian; +} + +impl BincodeByteOrder for BigEndian { + type Endian = byteorder::BigEndian; +} + +impl BincodeByteOrder for NativeEndian { + type Endian = byteorder::NativeEndian; +} + #[derive(Clone, Copy, Debug)] enum LimitOption { Unlimited, @@ -96,17 +280,25 @@ 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. #[derive(Clone, Debug)] +#[deprecated( + since = "1.3.0", + note = "please use the `DefaultOptions`/`OptionsExt` system instead" +)] pub struct Config { limit: LimitOption, endian: EndianOption, } -pub(crate) struct WithOtherLimit { +/// A configuration struct with a user-specified byte limit +#[derive(Clone, Copy)] +pub struct WithOtherLimit { _options: O, pub(crate) new_limit: L, } -pub(crate) struct WithOtherEndian { +/// A configuration struct with a user-specified endian order +#[derive(Clone, Copy)] +pub struct WithOtherEndian { options: O, _endian: PhantomData, } @@ -121,7 +313,7 @@ impl WithOtherLimit { } } -impl WithOtherEndian { +impl WithOtherEndian { #[inline(always)] pub(crate) fn new(options: O) -> WithOtherEndian { WithOtherEndian { @@ -131,7 +323,7 @@ impl WithOtherEndian { } } -impl Options for WithOtherEndian { +impl Options for WithOtherEndian { type Limit = O::Limit; type Endian = E; @@ -333,32 +525,39 @@ impl Config { ) -> Result { config_map!(self, opts => ::internal::deserialize_from_custom_seed(seed, reader, opts)) } +} - /// Executes the acceptor with a serde::Deserializer instance. - /// NOT A PART OF THE STABLE PUBLIC API - #[doc(hidden)] - pub fn with_deserializer<'a, A, R>(&self, reader: R, acceptor: A) -> A::Output - where - A: DeserializerAcceptor<'a>, - R: BincodeRead<'a>, - { - config_map!(self, opts => { - let mut deserializer = ::de::Deserializer::new(reader, opts); - acceptor.accept(&mut deserializer) - }) +mod internal { + use super::*; + use byteorder::ByteOrder; + + pub trait Options { + type Limit: SizeLimit + 'static; + type Endian: BincodeByteOrder + 'static; + + fn limit(&mut self) -> &mut Self::Limit; } - /// Executes the acceptor with a serde::Serializer instance. - /// NOT A PART OF THE STABLE PUBLIC API - #[doc(hidden)] - pub fn with_serializer(&self, writer: W, acceptor: A) -> A::Output - where - A: SerializerAcceptor, - W: Write, - { - config_map!(self, opts => { - let mut serializer = ::ser::Serializer::new(writer, opts); - acceptor.accept(&mut serializer) - }) + impl<'a, O: Options> Options for &'a mut O { + type Limit = O::Limit; + type Endian = O::Endian; + + #[inline(always)] + fn limit(&mut self) -> &mut Self::Limit { + (*self).limit() + } + } + + /// A trait for stopping serialization and deserialization when a certain limit has been reached. + pub trait SizeLimit { + /// Tells the SizeLimit that a certain number of bytes has been + /// read or written. Returns Err if the limit has been exceeded. + fn add(&mut self, n: u64) -> Result<()>; + /// Returns the hard limit (if one exists) + fn limit(&self) -> Option; + } + + pub trait BincodeByteOrder { + type Endian: ByteOrder + 'static; } } diff --git a/src/de/mod.rs b/src/de/mod.rs index 7db35e4..a38330c 100644 --- a/src/de/mod.rs +++ b/src/de/mod.rs @@ -1,14 +1,15 @@ -use config::Options; +use config::{BincodeByteOrder, Options}; use std::io::Read; -use self::read::BincodeRead; +use self::read::{BincodeRead, IoReader, SliceReader}; use byteorder::ReadBytesExt; -use internal::SizeLimit; +use config::SizeLimit; use serde; use serde::de::Error as DeError; use serde::de::IntoDeserializer; use {Error, ErrorKind, Result}; +/// Specialized ways to read data into bincode. pub mod read; /// A Deserializer that reads bytes from a buffer. @@ -24,14 +25,30 @@ pub mod read; /// serde::Deserialize::deserialize(&mut deserializer); /// let bytes_read = d.bytes_read(); /// ``` -pub(crate) struct Deserializer { +pub struct Deserializer { reader: R, options: O, } impl<'de, R: BincodeRead<'de>, O: Options> Deserializer { - /// Creates a new Deserializer with a given `Read`er and a size_limit. - pub(crate) fn new(r: R, options: O) -> Deserializer { + /// Creates a new Deserializer with a given `Read`er and options. + pub fn with_reader(r: IR, options: O) -> Deserializer, O> { + Deserializer { + reader: IoReader::new(r), + options, + } + } + + /// Creates a new Deserializer that will read from the given slice. + pub fn from_slice(slice: &'de [u8], options: O) -> Deserializer, O> { + Deserializer { + reader: SliceReader::new(slice), + options, + } + } + + /// Creates a new Deserializer with the given `BincodeRead`er + pub fn with_bincode_read(r: R, options: O) -> Deserializer { Deserializer { reader: r, options } } @@ -63,7 +80,7 @@ macro_rules! impl_nums { where V: serde::de::Visitor<'de>, { self.read_type::<$ty>()?; - let value = self.reader.$reader_method::()?; + let value = self.reader.$reader_method::<::Endian>()?; visitor.$visitor_method(value) } } diff --git a/src/de/read.rs b/src/de/read.rs index 6177eba..fdb6a1d 100644 --- a/src/de/read.rs +++ b/src/de/read.rs @@ -27,15 +27,11 @@ pub trait BincodeRead<'storage>: io::Read { } /// A BincodeRead implementation for byte slices -/// NOT A PART OF THE STABLE PUBLIC API -#[doc(hidden)] pub struct SliceReader<'storage> { slice: &'storage [u8], } -/// A BincodeRead implementation for io::Readers -/// NOT A PART OF THE STABLE PUBLIC API -#[doc(hidden)] +/// A BincodeRead implementation for `io::Read`ers pub struct IoReader { reader: R, temp_buffer: Vec, @@ -43,7 +39,7 @@ pub struct IoReader { impl<'storage> SliceReader<'storage> { /// Constructs a slice reader - pub fn new(bytes: &'storage [u8]) -> SliceReader<'storage> { + pub(crate) fn new(bytes: &'storage [u8]) -> SliceReader<'storage> { SliceReader { slice: bytes } } @@ -60,7 +56,7 @@ impl<'storage> SliceReader<'storage> { impl IoReader { /// Constructs an IoReadReader - pub fn new(r: R) -> IoReader { + pub(crate) fn new(r: R) -> IoReader { IoReader { reader: r, temp_buffer: vec![], diff --git a/src/internal.rs b/src/internal.rs index 968950a..f38eab9 100644 --- a/src/internal.rs +++ b/src/internal.rs @@ -2,15 +2,9 @@ use serde; use std::io::{Read, Write}; use std::marker::PhantomData; -use config::{Options, OptionsExt}; +use config::{Infinite, Options, OptionsExt, SizeLimit}; use de::read::BincodeRead; -use {ErrorKind, Result}; - -#[derive(Clone)] -struct CountSize { - total: u64, - other_limit: L, -} +use Result; pub(crate) fn serialize_into(writer: W, value: &T, mut options: O) -> Result<()> where @@ -42,35 +36,14 @@ where Ok(writer) } -impl SizeLimit for CountSize { - fn add(&mut self, c: u64) -> Result<()> { - self.other_limit.add(c)?; - self.total += c; - Ok(()) - } - - fn limit(&self) -> Option { - unreachable!(); - } -} - -pub(crate) fn serialized_size(value: &T, mut options: O) -> Result +pub(crate) fn serialized_size(value: &T, options: O) -> Result where T: serde::Serialize, { - let old_limiter = options.limit().clone(); - let mut size_counter = ::ser::SizeChecker { - options: ::config::WithOtherLimit::new( - options, - CountSize { - total: 0, - other_limit: old_limiter, - }, - ), - }; + let mut size_counter = ::ser::SizeChecker { options, total: 0 }; let result = value.serialize(&mut size_counter); - result.map(|_| size_counter.options.new_limit.total) + result.map(|_| size_counter.total) } pub(crate) fn deserialize_from(reader: R, options: O) -> Result @@ -111,7 +84,7 @@ where T: serde::de::DeserializeSeed<'a>, O: Options, { - let mut deserializer = ::de::Deserializer::<_, O>::new(reader, options); + let mut deserializer = ::de::Deserializer::<_, O>::with_bincode_read(reader, options); seed.deserialize(&mut deserializer) } @@ -121,7 +94,7 @@ where T: serde::de::Deserialize<'a>, O: Options, { - let mut deserializer = ::de::Deserializer::<_, _>::new(reader, options); + let mut deserializer = ::de::Deserializer::<_, _>::with_bincode_read(reader, options); serde::Deserialize::deserialize_in_place(&mut deserializer, place) } @@ -142,50 +115,3 @@ where let options = ::config::WithOtherLimit::new(options, Infinite); deserialize_from_custom_seed(seed, reader, options) } - -pub(crate) trait SizeLimit: Clone { - /// Tells the SizeLimit that a certain number of bytes has been - /// read or written. Returns Err if the limit has been exceeded. - fn add(&mut self, n: u64) -> Result<()>; - /// Returns the hard limit (if one exists) - fn limit(&self) -> Option; -} - -/// A SizeLimit that restricts serialized or deserialized messages from -/// exceeding a certain byte length. -#[derive(Copy, Clone)] -pub struct Bounded(pub u64); - -/// A SizeLimit without a limit! -/// Use this if you don't care about the size of encoded or decoded messages. -#[derive(Copy, Clone)] -pub struct Infinite; - -impl SizeLimit for Bounded { - #[inline(always)] - fn add(&mut self, n: u64) -> Result<()> { - if self.0 >= n { - self.0 -= n; - Ok(()) - } else { - Err(Box::new(ErrorKind::SizeLimit)) - } - } - - #[inline(always)] - fn limit(&self) -> Option { - Some(self.0) - } -} - -impl SizeLimit for Infinite { - #[inline(always)] - fn add(&mut self, _: u64) -> Result<()> { - Ok(()) - } - - #[inline(always)] - fn limit(&self) -> Option { - None - } -} diff --git a/src/lib.rs b/src/lib.rs index 2c12498..668314b 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -33,43 +33,20 @@ extern crate byteorder; #[macro_use] extern crate serde; -mod config; -mod de; +/// Configuration settings for bincode. +pub mod config; +/// Deserialize bincode data to a Rust data structure. +pub mod de; + mod error; mod internal; mod ser; -pub use config::Config; -pub use de::read::{BincodeRead, IoReader, SliceReader}; +pub use config::{Config, DefaultOptions, OptionsExt}; +pub use de::read::BincodeRead; +pub use de::Deserializer; pub use error::{Error, ErrorKind, Result}; - -/// An object that implements this trait can be passed a -/// serde::Deserializer without knowing its concrete type. -/// -/// This trait should be used only for `with_deserializer` functions. -#[doc(hidden)] -pub trait DeserializerAcceptor<'a> { - /// The return type for the accept method - type Output; - /// Accept a serde::Deserializer and do whatever you want with it. - fn accept(self, T) -> Self::Output - where - T: serde::Deserializer<'a, Error = Error>; -} - -/// An object that implements this trait can be passed a -/// serde::Serializer without knowing its concrete type. -/// -/// This trait should be used only for `with_serializer` functions. -#[doc(hidden)] -pub trait SerializerAcceptor { - /// The return type for the accept method - type Output; - /// Accept a serde::Serializer and do whatever you want with it. - fn accept(self, T) -> Self::Output - where - T: serde::Serializer; -} +pub use ser::Serializer; /// Get a default configuration object. /// @@ -79,6 +56,7 @@ pub trait SerializerAcceptor { /// |------------|------------| /// | Unlimited | Little | #[inline(always)] +#[deprecated(since = "1.3.0", note = "please use `DefaultOptions::new()` instead")] pub fn config() -> Config { Config::new() } @@ -92,7 +70,7 @@ where W: std::io::Write, T: serde::Serialize, { - config().serialize_into(writer, value) + DefaultOptions::new().serialize_into(writer, value) } /// Serializes a serializable object into a `Vec` of bytes using the default configuration. @@ -100,7 +78,7 @@ pub fn serialize(value: &T) -> Result> where T: serde::Serialize, { - config().serialize(value) + DefaultOptions::new().serialize(value) } /// Deserializes an object directly from a `Read`er using the default configuration. @@ -111,7 +89,7 @@ where R: std::io::Read, T: serde::de::DeserializeOwned, { - config().deserialize_from(reader) + DefaultOptions::new().deserialize_from(reader) } /// Deserializes an object from a custom `BincodeRead`er using the default configuration. @@ -124,7 +102,7 @@ where R: de::read::BincodeRead<'a>, T: serde::de::DeserializeOwned, { - config().deserialize_from_custom(reader) + DefaultOptions::new().deserialize_from_custom(reader) } /// Only use this if you know what you're doing. @@ -136,7 +114,7 @@ where T: serde::de::Deserialize<'a>, R: BincodeRead<'a>, { - config().deserialize_in_place(reader, place) + DefaultOptions::new().deserialize_in_place(reader, place) } /// Deserializes a slice of bytes into an instance of `T` using the default configuration. @@ -144,7 +122,7 @@ pub fn deserialize<'a, T>(bytes: &'a [u8]) -> Result where T: serde::de::Deserialize<'a>, { - config().deserialize(bytes) + DefaultOptions::new().deserialize(bytes) } /// Returns the size that an object would be if serialized using Bincode with the default configuration. @@ -152,27 +130,5 @@ pub fn serialized_size(value: &T) -> Result where T: serde::Serialize, { - config().serialized_size(value) -} - -/// Executes the acceptor with a serde::Deserializer instance. -/// NOT A PART OF THE STABLE PUBLIC API -#[doc(hidden)] -pub fn with_deserializer<'a, A, R>(reader: R, acceptor: A) -> A::Output -where - A: DeserializerAcceptor<'a>, - R: BincodeRead<'a>, -{ - config().with_deserializer(reader, acceptor) -} - -/// Executes the acceptor with a serde::Serializer instance. -/// NOT A PART OF THE STABLE PUBLIC API -#[doc(hidden)] -pub fn with_serializer(writer: W, acceptor: A) -> A::Output -where - A: SerializerAcceptor, - W: std::io::Write, -{ - config().with_serializer(writer, acceptor) + DefaultOptions::new().serialized_size(value) } diff --git a/src/ser/mod.rs b/src/ser/mod.rs index f353d60..442e34b 100644 --- a/src/ser/mod.rs +++ b/src/ser/mod.rs @@ -5,9 +5,9 @@ use serde; use byteorder::WriteBytesExt; -use super::internal::SizeLimit; +use super::config::SizeLimit; use super::{Error, ErrorKind, Result}; -use config::Options; +use config::{BincodeByteOrder, Options}; /// An Serializer that encodes values directly into a Writer. /// @@ -16,7 +16,7 @@ use config::Options; /// /// This struct should not be used often. /// For most cases, prefer the `encode_into` function. -pub(crate) struct Serializer { +pub struct Serializer { writer: W, _options: O, } @@ -61,15 +61,21 @@ impl<'a, W: Write, O: Options> serde::Serializer for &'a mut Serializer { } fn serialize_u16(self, v: u16) -> Result<()> { - self.writer.write_u16::(v).map_err(Into::into) + self.writer + .write_u16::<::Endian>(v) + .map_err(Into::into) } fn serialize_u32(self, v: u32) -> Result<()> { - self.writer.write_u32::(v).map_err(Into::into) + self.writer + .write_u32::<::Endian>(v) + .map_err(Into::into) } fn serialize_u64(self, v: u64) -> Result<()> { - self.writer.write_u64::(v).map_err(Into::into) + self.writer + .write_u64::<::Endian>(v) + .map_err(Into::into) } fn serialize_i8(self, v: i8) -> Result<()> { @@ -77,33 +83,43 @@ impl<'a, W: Write, O: Options> serde::Serializer for &'a mut Serializer { } fn serialize_i16(self, v: i16) -> Result<()> { - self.writer.write_i16::(v).map_err(Into::into) + self.writer + .write_i16::<::Endian>(v) + .map_err(Into::into) } fn serialize_i32(self, v: i32) -> Result<()> { - self.writer.write_i32::(v).map_err(Into::into) + self.writer + .write_i32::<::Endian>(v) + .map_err(Into::into) } fn serialize_i64(self, v: i64) -> Result<()> { - self.writer.write_i64::(v).map_err(Into::into) + self.writer + .write_i64::<::Endian>(v) + .map_err(Into::into) } serde_if_integer128! { fn serialize_u128(self, v: u128) -> Result<()> { - self.writer.write_u128::(v).map_err(Into::into) + self.writer.write_u128::<::Endian>(v).map_err(Into::into) } fn serialize_i128(self, v: i128) -> Result<()> { - self.writer.write_i128::(v).map_err(Into::into) + self.writer.write_i128::<::Endian>(v).map_err(Into::into) } } fn serialize_f32(self, v: f32) -> Result<()> { - self.writer.write_f32::(v).map_err(Into::into) + self.writer + .write_f32::<<::Endian as BincodeByteOrder>::Endian>(v) + .map_err(Into::into) } fn serialize_f64(self, v: f64) -> Result<()> { - self.writer.write_f64::(v).map_err(Into::into) + self.writer + .write_f64::<<::Endian as BincodeByteOrder>::Endian>(v) + .map_err(Into::into) } fn serialize_str(self, v: &str) -> Result<()> { @@ -221,11 +237,15 @@ impl<'a, W: Write, O: Options> serde::Serializer for &'a mut Serializer { pub(crate) struct SizeChecker { pub options: O, + pub total: u64, } impl SizeChecker { fn add_raw(&mut self, size: u64) -> Result<()> { - self.options.limit().add(size) + self.options.limit().add(size)?; + self.total += size; + + Ok(()) } fn add_value(&mut self, t: T) -> Result<()> { @@ -418,7 +438,7 @@ impl<'a, O: Options> serde::Serializer for &'a mut SizeChecker { } } -pub(crate) struct Compound<'a, W: 'a, O: Options + 'a> { +pub struct Compound<'a, W: 'a, O: Options + 'a> { ser: &'a mut Serializer, } diff --git a/tests/test.rs b/tests/test.rs index ffe81d0..201ed47 100644 --- a/tests/test.rs +++ b/tests/test.rs @@ -13,8 +13,8 @@ use std::fmt::{self, Debug}; use std::result::Result as StdResult; use bincode::{ - config, deserialize, deserialize_from, deserialize_in_place, serialize, serialized_size, - ErrorKind, Result, + deserialize, deserialize_from, deserialize_in_place, serialize, serialized_size, + DefaultOptions, ErrorKind, OptionsExt, Result, }; use serde::de::{Deserialize, DeserializeSeed, Deserializer, SeqAccess, Visitor}; @@ -33,10 +33,16 @@ where } { - let encoded = config().big_endian().serialize(&element).unwrap(); - let decoded = config().big_endian().deserialize(&encoded[..]).unwrap(); - let decoded_reader = config() - .big_endian() + 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(); @@ -259,11 +265,15 @@ fn deserializing_errors() { #[test] fn too_big_deserialize() { let serialized = vec![0, 0, 0, 3]; - let deserialized: Result = config().limit(3).deserialize_from(&mut &serialized[..]); + let deserialized: Result = DefaultOptions::new() + .with_limit(3) + .deserialize_from(&mut &serialized[..]); assert!(deserialized.is_err()); let serialized = vec![0, 0, 0, 3]; - let deserialized: Result = config().limit(4).deserialize_from(&mut &serialized[..]); + let deserialized: Result = DefaultOptions::new() + .with_limit(4) + .deserialize_from(&mut &serialized[..]); assert!(deserialized.is_ok()); } @@ -271,8 +281,8 @@ fn too_big_deserialize() { fn char_serialization() { let chars = "Aa\0☺♪"; for c in chars.chars() { - let encoded = config() - .limit(4) + let encoded = DefaultOptions::new() + .with_limit(4) .serialize(&c) .expect("serializing char failed"); let decoded: char = deserialize(&encoded).expect("deserializing failed"); @@ -283,18 +293,29 @@ fn char_serialization() { #[test] fn too_big_char_deserialize() { let serialized = vec![0x41]; - let deserialized: Result = config().limit(1).deserialize_from(&mut &serialized[..]); + let deserialized: Result = DefaultOptions::new() + .with_limit(1) + .deserialize_from(&mut &serialized[..]); assert!(deserialized.is_ok()); assert_eq!(deserialized.unwrap(), 'A'); } #[test] fn too_big_serialize() { - assert!(config().limit(3).serialize(&0u32).is_err()); - assert!(config().limit(4).serialize(&0u32).is_ok()); + assert!(DefaultOptions::new() + .with_limit(3) + .serialize(&0u32) + .is_err()); + assert!(DefaultOptions::new().with_limit(4).serialize(&0u32).is_ok()); - assert!(config().limit(8 + 4).serialize(&"abcde").is_err()); - assert!(config().limit(8 + 5).serialize(&"abcde").is_ok()); + assert!(DefaultOptions::new() + .with_limit(8 + 4) + .serialize(&"abcde") + .is_err()); + assert!(DefaultOptions::new() + .with_limit(8 + 5) + .serialize(&"abcde") + .is_ok()); } #[test] @@ -314,28 +335,82 @@ fn test_serialized_size() { #[test] fn test_serialized_size_bounded() { // JUST RIGHT - assert!(config().limit(1).serialized_size(&0u8).unwrap() == 1); - assert!(config().limit(2).serialized_size(&0u16).unwrap() == 2); - assert!(config().limit(4).serialized_size(&0u32).unwrap() == 4); - assert!(config().limit(8).serialized_size(&0u64).unwrap() == 8); - assert!(config().limit(8).serialized_size(&"").unwrap() == 8); - assert!(config().limit(8 + 1).serialized_size(&"a").unwrap() == 8 + 1); assert!( - config() - .limit(8 + 3 * 4) + DefaultOptions::new() + .with_limit(1) + .serialized_size(&0u8) + .unwrap() + == 1 + ); + assert!( + DefaultOptions::new() + .with_limit(2) + .serialized_size(&0u16) + .unwrap() + == 2 + ); + assert!( + DefaultOptions::new() + .with_limit(4) + .serialized_size(&0u32) + .unwrap() + == 4 + ); + assert!( + DefaultOptions::new() + .with_limit(8) + .serialized_size(&0u64) + .unwrap() + == 8 + ); + assert!( + DefaultOptions::new() + .with_limit(8) + .serialized_size(&"") + .unwrap() + == 8 + ); + assert!( + DefaultOptions::new() + .with_limit(8 + 1) + .serialized_size(&"a") + .unwrap() + == 8 + 1 + ); + assert!( + DefaultOptions::new() + .with_limit(8 + 3 * 4) .serialized_size(&vec![0u32, 1u32, 2u32]) .unwrap() == 8 + 3 * 4 ); // Below - assert!(config().limit(0).serialized_size(&0u8).is_err()); - assert!(config().limit(1).serialized_size(&0u16).is_err()); - assert!(config().limit(3).serialized_size(&0u32).is_err()); - 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) + assert!(DefaultOptions::new() + .with_limit(0) + .serialized_size(&0u8) + .is_err()); + assert!(DefaultOptions::new() + .with_limit(1) + .serialized_size(&0u16) + .is_err()); + assert!(DefaultOptions::new() + .with_limit(3) + .serialized_size(&0u32) + .is_err()); + assert!(DefaultOptions::new() + .with_limit(7) + .serialized_size(&0u64) + .is_err()); + assert!(DefaultOptions::new() + .with_limit(7) + .serialized_size(&"") + .is_err()); + assert!(DefaultOptions::new() + .with_limit(8 + 0) + .serialized_size(&"a") + .is_err()); + assert!(DefaultOptions::new() + .with_limit(8 + 3 * 4 - 1) .serialized_size(&vec![0u32, 1u32, 2u32]) .is_err()); } @@ -416,15 +491,15 @@ fn test_oom_protection() { len: u64, byte: u8, } - let x = config() - .limit(10) + let x = DefaultOptions::new() + .with_limit(10) .serialize(&FakeVec { len: 0xffffffffffffffffu64, byte: 1, }) .unwrap(); - let y: Result> = config() - .limit(10) + let y: Result> = DefaultOptions::new() + .with_limit(10) .deserialize_from(&mut Cursor::new(&x[..])); assert!(y.is_err()); } @@ -458,7 +533,10 @@ fn serde_bytes() { fn endian_difference() { let x = 10u64; let little = serialize(&x).unwrap(); - let big = config().big_endian().serialize(&x).unwrap(); + let big = DefaultOptions::new() + .with_big_endian() + .serialize(&x) + .unwrap(); assert_ne!(little, big); } @@ -647,7 +725,7 @@ where #[test] fn test_default_deserialize_seed() { - let config = config(); + let config = DefaultOptions::new(); let data: Vec<_> = (10..100).collect(); let bytes = config.serialize(&data).expect("Config::serialize failed"); @@ -665,8 +743,7 @@ fn test_default_deserialize_seed() { #[test] fn test_big_endian_deserialize_seed() { - let mut config = config(); - config.big_endian(); + let config = DefaultOptions::new().with_big_endian(); let data: Vec<_> = (10..100).collect(); let bytes = config.serialize(&data).expect("Config::serialize failed"); @@ -684,7 +761,7 @@ fn test_big_endian_deserialize_seed() { #[test] fn test_default_deserialize_from_seed() { - let config = config(); + let config = DefaultOptions::new(); let data: Vec<_> = (10..100).collect(); let bytes = config.serialize(&data).expect("Config::serialize failed"); @@ -702,8 +779,7 @@ fn test_default_deserialize_from_seed() { #[test] fn test_big_endian_deserialize_from_seed() { - let mut config = config(); - config.big_endian(); + let config = DefaultOptions::new().with_big_endian(); let data: Vec<_> = (10..100).collect(); let bytes = config.serialize(&data).expect("Config::serialize failed");