From b31151a60539605e3056932e18de767781357061 Mon Sep 17 00:00:00 2001 From: Ty Overby Date: Wed, 7 Feb 2018 18:26:46 -0800 Subject: [PATCH] 2nd implementation of the Config Trait (#214) * add option and config traits * thread options everywhere * add WithOtherLimit, WithOtherEndian, and update internal to take advantage of it * wip * add rest of the public API and fix tests * dtolnay feedback * remove serialized_size_bounded and replace it with a use of config * remove inline from trait method * finish documentation and add custom reader support * minor config_map refactor * doc changes * add with_(de)serializer functions and their associated modules --- examples/basic.rs | 4 +- src/config.rs | 297 +++++++++++++++++++++++++++++++++++++++++ src/de/mod.rs | 61 ++++----- src/de/read.rs | 26 ++-- src/error.rs | 119 +++++++++++++++++ src/internal.rs | 332 +++++++++++++++------------------------------- src/lib.rs | 237 +++++++++++++-------------------- src/ser/mod.rs | 128 +++++++++--------- tests/test.rs | 175 ++++++++++++------------ 9 files changed, 811 insertions(+), 568 deletions(-) create mode 100644 src/config.rs create mode 100644 src/error.rs diff --git a/examples/basic.rs b/examples/basic.rs index 04e48c4..4b46307 100644 --- a/examples/basic.rs +++ b/examples/basic.rs @@ -2,7 +2,7 @@ extern crate serde_derive; extern crate bincode; -use bincode::{deserialize, serialize, Infinite}; +use bincode::{deserialize, serialize}; #[derive(Serialize, Deserialize, PartialEq, Debug)] struct Entity { @@ -16,7 +16,7 @@ struct World(Vec); fn main() { let world = World(vec![Entity { x: 0.0, y: 4.0 }, Entity { x: 10.0, y: 20.5 }]); - let encoded: Vec = serialize(&world, Infinite).unwrap(); + let encoded: Vec = serialize(&world).unwrap(); // 8 bytes for the length of the vector (usize), 4 bytes per float. assert_eq!(encoded.len(), 8 + 4 * 4); diff --git a/src/config.rs b/src/config.rs new file mode 100644 index 0000000..90bcce9 --- /dev/null +++ b/src/config.rs @@ -0,0 +1,297 @@ +use super::internal::{Bounded, Infinite, SizeLimit}; +use ::error::Result; +use byteorder::{BigEndian, ByteOrder, LittleEndian, NativeEndian}; +use {DeserializerAcceptor, SerializerAcceptor}; +use serde; +use std::io::{Write, Read}; +use std::marker::PhantomData; +use de::read::BincodeRead; + +use self::LimitOption::*; +use self::EndianOption::*; + +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 {} + +impl DefaultOptions { + fn new() -> DefaultOptions { + DefaultOptions(Infinite) + } +} + +impl Options for DefaultOptions { + type Limit = Infinite; + type Endian = LittleEndian; + + #[inline(always)] + fn limit(&mut self) -> &mut Infinite { + &mut self.0 + } +} + +#[derive(Clone, Copy)] +enum LimitOption { + Unlimited, + Limited(u64), +} + +#[derive(Clone, Copy)] +enum EndianOption { + Big, + Little, + Native, +} + +/// A configuration builder 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. +pub struct Config { + limit: LimitOption, + endian: EndianOption, +} + +pub(crate) struct WithOtherLimit { + _options: O, + pub(crate) new_limit: L, +} + +pub(crate) struct WithOtherEndian { + options: O, + _endian: PhantomData, +} + + +impl WithOtherLimit { + #[inline(always)] + pub(crate) fn new(options: O, limit: L) -> WithOtherLimit { + WithOtherLimit { + _options: options, + new_limit: limit, + } + } +} + +impl WithOtherEndian { + #[inline(always)] + pub(crate) fn new(options: O) -> WithOtherEndian { + WithOtherEndian { + options: options, + _endian: PhantomData, + } + } +} + +impl Options for WithOtherEndian { + type Limit = O::Limit; + type Endian = E; + + #[inline(always)] + fn limit(&mut self) -> &mut O::Limit { + self.options.limit() + } +} + +impl Options for WithOtherLimit { + type Limit = L; + type Endian = O::Endian; + + fn limit(&mut self) -> &mut L { + &mut self.new_limit + } +} + +macro_rules! config_map { + ($self:expr, $opts:ident => $call:expr) => { + match ($self.limit, $self.endian) { + (Unlimited, Little) => { + let $opts = DefaultOptions::new().with_no_limit().with_little_endian(); + $call + } + (Unlimited, Big) => { + let $opts = DefaultOptions::new().with_no_limit().with_big_endian(); + $call + } + (Unlimited, Native) => { + let $opts = DefaultOptions::new().with_no_limit().with_native_endian(); + $call + } + + (Limited(l), Little) => { + let $opts = DefaultOptions::new().with_limit(l).with_little_endian(); + $call + } + (Limited(l), Big) => { + let $opts = DefaultOptions::new().with_limit(l).with_big_endian(); + $call + } + (Limited(l), Native) => { + let $opts = DefaultOptions::new().with_limit(l).with_native_endian(); + $call + } + } + } +} + +impl Config { + #[inline(always)] + pub(crate) fn new() -> Config { + Config { + limit: LimitOption::Unlimited, + endian: EndianOption::Little, + } + } + + /// Sets the byte limit to be unlimited. + /// This is the default. + #[inline(always)] + pub fn no_limit(&mut self) -> &mut Self { + self.limit = LimitOption::Unlimited; + self + } + + /// Sets the byte limit to `limit`. + #[inline(always)] + pub fn limit(&mut self, limit: u64) -> &mut Self { + self.limit = LimitOption::Limited(limit); + self + } + + /// Sets the endianness to little-endian + /// This is the default. + #[inline(always)] + pub fn little_endian(&mut self) -> &mut Self { + self.endian = EndianOption::Little; + self + } + + /// Sets the endianness to big-endian + #[inline(always)] + pub fn big_endian(&mut self) -> &mut Self { + self.endian= EndianOption::Big; + self + } + + /// Sets the endianness to the the machine-native endianness + #[inline(always)] + pub fn native_endian(&mut self) -> &mut Self { + self.endian = EndianOption::Native; + self + } + + /// Serializes a serializable object into a `Vec` of bytes using this configuration + #[inline(always)] + pub fn serialize(&self, t: &T) -> Result> { + config_map!(self, opts => ::internal::serialize(t, opts)) + } + + /// Returns the size that an object would be if serialized using Bincode with this configuration + #[inline(always)] + pub fn serialized_size(&self, t: &T) -> Result { + config_map!(self, opts => ::internal::serialized_size(t, opts)) + } + + /// 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)] + pub fn serialize_into(&self, w: W, t: &T) -> Result<()> { + config_map!(self, opts => ::internal::serialize_into(w, t, opts)) + } + + /// Deserializes a slice of bytes into an instance of `T` using this configuration + #[inline(always)] + pub fn deserialize<'a, T: serde::Deserialize<'a>>(&self, bytes: &'a [u8]) -> Result { + config_map!(self, opts => ::internal::deserialize(bytes, opts)) + } + + /// 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)] + pub fn deserialize_from(&self, reader: R) -> Result { + config_map!(self, opts => ::internal::deserialize_from(reader, opts)) + } + + /// 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)] + pub fn deserialize_from_custom<'a, R: BincodeRead<'a>, T: serde::de::DeserializeOwned>(&self, reader: R) -> Result { + config_map!(self, opts => ::internal::deserialize_from_custom(reader, opts)) + } + + /// Executes the acceptor with a serde::Deserializer instance. + 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) + }) + } + + /// Executes the acceptor with a serde::Serializer instance. + 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) + }) + } +} diff --git a/src/de/mod.rs b/src/de/mod.rs index 284d5fd..8f2c2cd 100644 --- a/src/de/mod.rs +++ b/src/de/mod.rs @@ -1,12 +1,12 @@ use std::io::Read; -use std::marker::PhantomData; +use ::config::Options; -use byteorder::{ReadBytesExt, ByteOrder}; -use serde_crate as serde; -use serde_crate::de::IntoDeserializer; -use serde_crate::de::Error as DeError; -use SizeLimit; -use super::{Result, Error, ErrorKind}; +use serde; +use byteorder::ReadBytesExt; +use serde::de::IntoDeserializer; +use serde::de::Error as DeError; +use ::{Error, ErrorKind, Result}; +use ::internal::SizeLimit; use self::read::BincodeRead; pub mod read; @@ -24,24 +24,22 @@ pub mod read; /// serde::Deserialize::deserialize(&mut deserializer); /// let bytes_read = d.bytes_read(); /// ``` -pub struct Deserializer { +pub(crate) struct Deserializer { reader: R, - size_limit: S, - _phantom: PhantomData, + options: O, } -impl<'de, R: BincodeRead<'de>, E: ByteOrder, S: SizeLimit> Deserializer { +impl<'de, R: BincodeRead<'de>, O: Options> Deserializer { /// Creates a new Deserializer with a given `Read`er and a size_limit. - pub fn new(r: R, size_limit: S) -> Deserializer { + pub(crate) fn new(r: R, options: O) -> Deserializer { Deserializer { reader: r, - size_limit: size_limit, - _phantom: PhantomData, + options: options, } } fn read_bytes(&mut self, count: u64) -> Result<()> { - self.size_limit.add(count) + self.options.limit().add(count) } fn read_type(&mut self) -> Result<()> { @@ -68,17 +66,16 @@ macro_rules! impl_nums { where V: serde::de::Visitor<'de>, { try!(self.read_type::<$ty>()); - let value = try!(self.reader.$reader_method::()); + let value = try!(self.reader.$reader_method::()); visitor.$visitor_method(value) } } } -impl<'de, 'a, R, S, E> serde::Deserializer<'de> for &'a mut Deserializer +impl<'de, 'a, R, O> serde::Deserializer<'de> for &'a mut Deserializer where R: BincodeRead<'de>, - S: SizeLimit, - E: ByteOrder, + O: Options, { type Error = Error; @@ -211,8 +208,8 @@ where where V: serde::de::Visitor<'de>, { - impl<'de, 'a, R: 'a, S, E> serde::de::EnumAccess<'de> for &'a mut Deserializer - where R: BincodeRead<'de>, S: SizeLimit, E: ByteOrder { + impl<'de, 'a, R: 'a, O> serde::de::EnumAccess<'de> for &'a mut Deserializer + where R: BincodeRead<'de>, O: Options { type Error = Error; type Variant = Self; @@ -232,8 +229,8 @@ where where V: serde::de::Visitor<'de>, { - struct Access<'a, R: Read + 'a, S: SizeLimit + 'a, E: ByteOrder + 'a> { - deserializer: &'a mut Deserializer, + struct Access<'a, R: Read + 'a, O: Options + 'a> { + deserializer: &'a mut Deserializer, len: usize, } @@ -242,9 +239,8 @@ where 'a, 'b: 'a, R: BincodeRead<'de> + 'b, - S: SizeLimit, - E: ByteOrder, - > serde::de::SeqAccess<'de> for Access<'a, R, S, E> { + O: Options, + > serde::de::SeqAccess<'de> for Access<'a, R, O> { type Error = Error; fn next_element_seed(&mut self, seed: T) -> Result> @@ -299,8 +295,8 @@ where where V: serde::de::Visitor<'de>, { - struct Access<'a, R: Read + 'a, S: SizeLimit + 'a, E: ByteOrder + 'a> { - deserializer: &'a mut Deserializer, + struct Access<'a, R: Read + 'a, O: Options + 'a> { + deserializer: &'a mut Deserializer, len: usize, } @@ -309,9 +305,8 @@ where 'a, 'b: 'a, R: BincodeRead<'de> + 'b, - S: SizeLimit, - E: ByteOrder, - > serde::de::MapAccess<'de> for Access<'a, R, S, E> { + O: Options, + > serde::de::MapAccess<'de> for Access<'a, R, O> { type Error = Error; fn next_key_seed(&mut self, seed: K) -> Result> @@ -413,8 +408,8 @@ where } } -impl<'de, 'a, R, S, E> serde::de::VariantAccess<'de> for &'a mut Deserializer -where R: BincodeRead<'de>, S: SizeLimit, E: ByteOrder { +impl<'de, 'a, R, O> serde::de::VariantAccess<'de> for &'a mut Deserializer +where R: BincodeRead<'de>, O: Options{ type Error = Error; fn unit_variant(self) -> Result<()> { diff --git a/src/de/read.rs b/src/de/read.rs index de20cbd..722cab1 100644 --- a/src/de/read.rs +++ b/src/de/read.rs @@ -1,19 +1,21 @@ use std::io; -use Result; -use serde_crate as serde; +use error::Result; +use serde; -/// A byte-oriented reading trait that is specialized for -/// slices and generic readers. -pub trait BincodeRead<'storage>: io::Read + ::private::Sealed { - #[doc(hidden)] +/// An optional Read trait for advanced Bincode usage. +/// +/// It is highly recommended to use bincode with `io::Read` or `&[u8]` before +/// implementing a custom `BincodeRead`. +pub trait BincodeRead<'storage>: io::Read { + /// Forwards reading `length` bytes of a string on to the serde reader. fn forward_read_str(&mut self, length: usize, visitor: V) -> Result where V: serde::de::Visitor<'storage>; - #[doc(hidden)] + /// Return the first `length` bytes of the internal byte buffer. fn get_byte_buffer(&mut self, length: usize) -> Result>; - #[doc(hidden)] + /// Forwards reading `length` bytes on to the serde reader. fn forward_read_bytes(&mut self, length: usize, visitor: V) -> Result where V: serde::de::Visitor<'storage>; @@ -48,24 +50,29 @@ impl IoReader { } impl<'storage> io::Read for SliceReader<'storage> { + #[inline(always)] fn read(&mut self, out: &mut [u8]) -> io::Result { (&mut self.slice).read(out) } + #[inline(always)] fn read_exact(&mut self, out: &mut [u8]) -> io::Result<()> { (&mut self.slice).read_exact(out) } } impl io::Read for IoReader { + #[inline(always)] fn read(&mut self, out: &mut [u8]) -> io::Result { self.reader.read(out) } + #[inline(always)] fn read_exact(&mut self, out: &mut [u8]) -> io::Result<()> { self.reader.read_exact(out) } } impl<'storage> SliceReader<'storage> { + #[inline(always)] fn unexpected_eof() -> Box<::ErrorKind> { return Box::new(::ErrorKind::Io( io::Error::new(io::ErrorKind::UnexpectedEof, ""), @@ -74,6 +81,7 @@ impl<'storage> SliceReader<'storage> { } impl<'storage> BincodeRead<'storage> for SliceReader<'storage> { + #[inline(always)] fn forward_read_str(&mut self, length: usize, visitor: V) -> Result where V: serde::de::Visitor<'storage>, @@ -92,6 +100,7 @@ impl<'storage> BincodeRead<'storage> for SliceReader<'storage> { r } + #[inline(always)] fn get_byte_buffer(&mut self, length: usize) -> Result> { if length > self.slice.len() { return Err(SliceReader::unexpected_eof()); @@ -102,6 +111,7 @@ impl<'storage> BincodeRead<'storage> for SliceReader<'storage> { Ok(r.to_vec()) } + #[inline(always)] fn forward_read_bytes(&mut self, length: usize, visitor: V) -> Result where V: serde::de::Visitor<'storage>, diff --git a/src/error.rs b/src/error.rs new file mode 100644 index 0000000..f5cfca3 --- /dev/null +++ b/src/error.rs @@ -0,0 +1,119 @@ +use std::io; +use std::{error, fmt}; +use std::str::Utf8Error; +use std::error::Error as StdError; + +use serde; + +/// The result of a serialization or deserialization operation. +pub type Result = ::std::result::Result; + +/// An error that can be produced during (de)serializing. +pub type Error = Box; + +/// The kind of error that can be produced during a serialization or deserialization. +#[derive(Debug)] +pub enum ErrorKind { + /// If the error stems from the reader/writer that is being used + /// during (de)serialization, that error will be stored and returned here. + Io(io::Error), + /// Returned if the deserializer attempts to deserialize a string that is not valid utf8 + InvalidUtf8Encoding(Utf8Error), + /// Returned if the deserializer attempts to deserialize a bool that was + /// not encoded as either a 1 or a 0 + InvalidBoolEncoding(u8), + /// Returned if the deserializer attempts to deserialize a char that is not in the correct format. + InvalidCharEncoding, + /// Returned if the deserializer attempts to deserialize the tag of an enum that is + /// not in the expected ranges + InvalidTagEncoding(usize), + /// Serde has a deserialize_any method that lets the format hint to the + /// object which route to take in deserializing. + DeserializeAnyNotSupported, + /// If (de)serializing a message takes more than the provided size limit, this + /// error is returned. + SizeLimit, + /// Bincode can not encode sequences of unknown length (like iterators). + SequenceMustHaveLength, + /// A custom error message from Serde. + Custom(String), +} + +impl StdError for ErrorKind { + fn description(&self) -> &str { + match *self { + ErrorKind::Io(ref err) => error::Error::description(err), + ErrorKind::InvalidUtf8Encoding(_) => "string is not valid utf8", + ErrorKind::InvalidBoolEncoding(_) => "invalid u8 while decoding bool", + ErrorKind::InvalidCharEncoding => "char is not valid", + ErrorKind::InvalidTagEncoding(_) => "tag for enum is not valid", + ErrorKind::SequenceMustHaveLength => + "Bincode can only encode sequences and maps that have a knowable size ahead of time", + ErrorKind::DeserializeAnyNotSupported => { + "Bincode doesn't support serde::Deserializer::deserialize_any" + } + ErrorKind::SizeLimit => "the size limit has been reached", + ErrorKind::Custom(ref msg) => msg, + + } + } + + fn cause(&self) -> Option<&error::Error> { + match *self { + ErrorKind::Io(ref err) => Some(err), + ErrorKind::InvalidUtf8Encoding(_) => None, + ErrorKind::InvalidBoolEncoding(_) => None, + ErrorKind::InvalidCharEncoding => None, + ErrorKind::InvalidTagEncoding(_) => None, + ErrorKind::SequenceMustHaveLength => None, + ErrorKind::DeserializeAnyNotSupported => None, + ErrorKind::SizeLimit => None, + ErrorKind::Custom(_) => None, + } + } +} + +impl From for Error { + fn from(err: io::Error) -> Error { + ErrorKind::Io(err).into() + } +} + +impl fmt::Display for ErrorKind { + fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { + match *self { + ErrorKind::Io(ref ioerr) => write!(fmt, "io error: {}", ioerr), + ErrorKind::InvalidUtf8Encoding(ref e) => write!(fmt, "{}: {}", self.description(), e), + ErrorKind::InvalidBoolEncoding(b) => { + write!(fmt, "{}, expected 0 or 1, found {}", self.description(), b) + } + ErrorKind::InvalidCharEncoding => write!(fmt, "{}", self.description()), + ErrorKind::InvalidTagEncoding(tag) => { + write!(fmt, "{}, found {}", self.description(), tag) + } + ErrorKind::SequenceMustHaveLength => { + write!(fmt, "{}", self.description()) + } + ErrorKind::SizeLimit => write!(fmt, "{}", self.description()), + ErrorKind::DeserializeAnyNotSupported => { + write!( + fmt, + "Bincode does not support the serde::Deserializer::deserialize_any method" + ) + } + ErrorKind::Custom(ref s) => s.fmt(fmt), + } + } +} + +impl serde::de::Error for Error { + fn custom(desc: T) -> Error { + ErrorKind::Custom(desc.to_string()).into() + } +} + +impl serde::ser::Error for Error { + fn custom(msg: T) -> Self { + ErrorKind::Custom(msg.to_string()).into() + } +} diff --git a/src/internal.rs b/src/internal.rs index 396bb5e..66cae64 100644 --- a/src/internal.rs +++ b/src/internal.rs @@ -1,199 +1,50 @@ -//! A collection of serialization and deserialization functions -//! that use the `serde` crate for the serializable and deserializable -//! implementation. +use std::io::{Read, Write}; +use serde; -use std::io::{self, Write, Read}; -use std::{error, fmt, result}; -use std::str::Utf8Error; -use {CountSize, SizeLimit}; -use byteorder::ByteOrder; -use std::error::Error as StdError; +use config::{Options, OptionsExt}; +use de::read::BincodeRead; +use {ErrorKind, Result}; -pub use super::de::Deserializer; - -pub use super::ser::Serializer; - -use super::ser::SizeChecker; - -use serde_crate as serde; - -/// The result of a serialization or deserialization operation. -pub type Result = result::Result; - -/// An error that can be produced during (de)serializing. -pub type Error = Box; - -/// The kind of error that can be produced during a serialization or deserialization. -#[derive(Debug)] -pub enum ErrorKind { - /// If the error stems from the reader/writer that is being used - /// during (de)serialization, that error will be stored and returned here. - Io(io::Error), - /// Returned if the deserializer attempts to deserialize a string that is not valid utf8 - InvalidUtf8Encoding(Utf8Error), - /// Returned if the deserializer attempts to deserialize a bool that was - /// not encoded as either a 1 or a 0 - InvalidBoolEncoding(u8), - /// Returned if the deserializer attempts to deserialize a char that is not in the correct format. - InvalidCharEncoding, - /// Returned if the deserializer attempts to deserialize the tag of an enum that is - /// not in the expected ranges - InvalidTagEncoding(usize), - /// Serde has a deserialize_any method that lets the format hint to the - /// object which route to take in deserializing. - DeserializeAnyNotSupported, - /// If (de)serializing a message takes more than the provided size limit, this - /// error is returned. - SizeLimit, - /// Bincode can not encode sequences of unknown length (like iterators). - SequenceMustHaveLength, - /// A custom error message from Serde. - Custom(String), +#[derive(Clone)] +struct CountSize { + total: u64, + other_limit: L, } -impl StdError for ErrorKind { - fn description(&self) -> &str { - match *self { - ErrorKind::Io(ref err) => error::Error::description(err), - ErrorKind::InvalidUtf8Encoding(_) => "string is not valid utf8", - ErrorKind::InvalidBoolEncoding(_) => "invalid u8 while decoding bool", - ErrorKind::InvalidCharEncoding => "char is not valid", - ErrorKind::InvalidTagEncoding(_) => "tag for enum is not valid", - ErrorKind::SequenceMustHaveLength => - "Bincode can only encode sequences and maps that have a knowable size ahead of time", - ErrorKind::DeserializeAnyNotSupported => { - "Bincode doesn't support serde::Deserializer::deserialize_any" - } - ErrorKind::SizeLimit => "the size limit has been reached", - ErrorKind::Custom(ref msg) => msg, - - } - } - - fn cause(&self) -> Option<&error::Error> { - match *self { - ErrorKind::Io(ref err) => Some(err), - ErrorKind::InvalidUtf8Encoding(_) => None, - ErrorKind::InvalidBoolEncoding(_) => None, - ErrorKind::InvalidCharEncoding => None, - ErrorKind::InvalidTagEncoding(_) => None, - ErrorKind::SequenceMustHaveLength => None, - ErrorKind::DeserializeAnyNotSupported => None, - ErrorKind::SizeLimit => None, - ErrorKind::Custom(_) => None, - } - } -} - -impl From for Error { - fn from(err: io::Error) -> Error { - ErrorKind::Io(err).into() - } -} - -impl fmt::Display for ErrorKind { - fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { - match *self { - ErrorKind::Io(ref ioerr) => write!(fmt, "io error: {}", ioerr), - ErrorKind::InvalidUtf8Encoding(ref e) => write!(fmt, "{}: {}", self.description(), e), - ErrorKind::InvalidBoolEncoding(b) => { - write!(fmt, "{}, expected 0 or 1, found {}", self.description(), b) - } - ErrorKind::InvalidCharEncoding => write!(fmt, "{}", self.description()), - ErrorKind::InvalidTagEncoding(tag) => { - write!(fmt, "{}, found {}", self.description(), tag) - } - ErrorKind::SequenceMustHaveLength => { - write!(fmt, "{}", self.description()) - } - ErrorKind::SizeLimit => write!(fmt, "{}", self.description()), - ErrorKind::DeserializeAnyNotSupported => { - write!( - fmt, - "Bincode does not support the serde::Deserializer::deserialize_any method" - ) - } - ErrorKind::Custom(ref s) => s.fmt(fmt), - } - } -} - -impl serde::de::Error for Error { - fn custom(desc: T) -> Error { - ErrorKind::Custom(desc.to_string()).into() - } -} - -impl serde::ser::Error for Error { - fn custom(msg: T) -> Self { - ErrorKind::Custom(msg.to_string()).into() - } -} - -/// Serializes an object directly into a `Writer`. -/// -/// If the serialization would take more bytes than allowed by `size_limit`, an error -/// is returned and *no bytes* will be written into the `Writer`. -/// -/// If this returns an `Error` (other than SizeLimit), assume that the -/// writer is in an invalid state, as writing could bail out in the middle of -/// serializing. -pub fn serialize_into(writer: W, value: &T, size_limit: S) -> Result<()> +pub(crate) fn serialize_into(writer: W, value: &T, mut options: O) -> Result<()> where W: Write, T: serde::Serialize, - S: SizeLimit, - E: ByteOrder, + O: Options, { - if let Some(limit) = size_limit.limit() { - try!(serialized_size_bounded(value, limit).ok_or( - ErrorKind::SizeLimit, - )); + if options.limit().limit().is_some() { + // "compute" the size for the side-effect + // of returning Err if the bound was reached. + serialized_size(value, &mut options)?; } - let mut serializer = Serializer::<_, E>::new(writer); + let mut serializer = ::ser::Serializer::<_, O>::new(writer, options); serde::Serialize::serialize(value, &mut serializer) } -/// Serializes a serializable object into a `Vec` of bytes. -/// -/// If the serialization would take more bytes than allowed by `size_limit`, -/// an error is returned. -pub fn serialize(value: &T, size_limit: S) -> Result> +pub(crate) fn serialize(value: &T, mut options: O) -> Result> where T: serde::Serialize, - S: SizeLimit, - E: ByteOrder, + O: Options, { - let mut writer = match size_limit.limit() { - Some(size_limit) => { - let actual_size = try!(serialized_size_bounded(value, size_limit).ok_or( - ErrorKind::SizeLimit, - )); - Vec::with_capacity(actual_size as usize) - } - None => { - let size = serialized_size(value) as usize; - Vec::with_capacity(size) - } + let mut writer = { + let actual_size = serialized_size(value, &mut options)?; + Vec::with_capacity(actual_size as usize) }; - try!(serialize_into::<_, _, _, E>( - &mut writer, - value, - super::Infinite, - )); + serialize_into(&mut writer, value, options.with_no_limit())?; Ok(writer) } -impl SizeLimit for CountSize { +impl SizeLimit for CountSize { fn add(&mut self, c: u64) -> Result<()> { + self.other_limit.add(c)?; self.total += c; - if let Some(limit) = self.limit { - if self.total > limit { - return Err(Box::new(ErrorKind::SizeLimit)); - } - } Ok(()) } @@ -202,77 +53,102 @@ impl SizeLimit for CountSize { } } -/// Returns the size that an object would be if serialized using Bincode. -/// -/// This is used internally as part of the check for encode_into, but it can -/// be useful for preallocating buffers if thats your style. -pub fn serialized_size(value: &T) -> u64 +pub(crate) fn serialized_size(value: &T, mut options: O) -> Result where T: serde::Serialize, { - let mut size_counter = SizeChecker { - size_limit: CountSize { - total: 0, - limit: None, - }, + let old_limiter = options.limit().clone(); + let mut size_counter = ::ser::SizeChecker { + options: ::config::WithOtherLimit::new( + options, + CountSize { + total: 0, + other_limit: old_limiter, + }, + ), }; - value.serialize(&mut size_counter).ok(); - size_counter.size_limit.total + let result = value.serialize(&mut size_counter); + result.map(|_| size_counter.options.new_limit.total) } -/// Given a maximum size limit, check how large an object would be if it -/// were to be serialized. -/// -/// If it can be serialized in `max` or fewer bytes, that number will be returned -/// inside `Some`. If it goes over bounds, then None is returned. -pub fn serialized_size_bounded(value: &T, max: u64) -> Option -where - T: serde::Serialize, -{ - let mut size_counter = SizeChecker { - size_limit: CountSize { - total: 0, - limit: Some(max), - }, - }; - - match value.serialize(&mut size_counter) { - Ok(_) => Some(size_counter.size_limit.total), - Err(_) => None, - } -} - -/// Deserializes an object directly from a `Read`er. -/// -/// If the provided `SizeLimit` is reached, the deserialization will bail immediately. -/// A SizeLimit can help prevent an attacker from flooding your server with -/// a neverending stream of values that runs your server out of memory. -/// -/// If this returns an `Error`, assume that the buffer that you passed -/// in is in an invalid state, as the error could be returned during any point -/// in the reading. -pub fn deserialize_from(reader: R, size_limit: S) -> Result +pub(crate) fn deserialize_from(reader: R, options: O) -> Result where R: Read, T: serde::de::DeserializeOwned, - S: SizeLimit, - E: ByteOrder, + O: Options, { let reader = ::de::read::IoReader::new(reader); - let mut deserializer = Deserializer::<_, S, E>::new(reader, size_limit); + let mut deserializer = ::de::Deserializer::<_, O>::new(reader, options); serde::Deserialize::deserialize(&mut deserializer) } -/// Deserializes a slice of bytes into an object. -/// -/// This method does not have a size-limit because if you already have the bytes -/// in memory, then you don't gain anything by having a limiter. -pub fn deserialize<'a, T, E: ByteOrder>(bytes: &'a [u8]) -> Result +pub(crate) fn deserialize_from_custom<'a, R, T, O>(reader: R, options: O) -> Result where - T: serde::de::Deserialize<'a>, + R: BincodeRead<'a>, + T: serde::de::DeserializeOwned, + O: Options, { - let reader = ::de::read::SliceReader::new(bytes); - let mut deserializer = Deserializer::<_, _, E>::new(reader, super::Infinite); + let mut deserializer = ::de::Deserializer::<_, O>::new(reader, options); serde::Deserialize::deserialize(&mut deserializer) } + +pub(crate) fn deserialize<'a, T, O>(bytes: &'a [u8], options: O) -> Result +where + T: serde::de::Deserialize<'a>, + O: Options, +{ + let reader = ::de::read::SliceReader::new(bytes); + let options = ::config::WithOtherLimit::new(options, Infinite); + let mut deserializer = ::de::Deserializer::new(reader, options); + serde::Deserialize::deserialize(&mut deserializer) +} + + +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 15c6bc8..6623d83 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,32 +1,20 @@ #![deny(missing_docs)] //! Bincode is a crate for encoding and decoding using a tiny binary -//! serialization strategy. -//! -//! There are simple functions for encoding to `Vec` and decoding from -//! `&[u8]`, but the meat of the library is the `serialize_into` and `deserialize_from` -//! functions which respectively allow encoding into any `std::io::Write` -//! or decode from any `std::io::Read`. -//! -//! ## Modules -//! Until "default type parameters" lands, we have an extra module called `endian_choice` -//! that duplicates all of the core Bincode functionality but with the option to choose -//! which endianness the integers are encoded using. -//! -//! The default endianness is little. +//! serialization strategy. Using it, you can easily go from having +//! an object in memory, quickly serialize it to bytes, and then +//! deserialize it back just as fast! //! //! ### Using Basic Functions //! //! ```rust //! extern crate bincode; -//! use bincode::{serialize, deserialize, Bounded}; +//! use bincode::{serialize, deserialize}; //! fn main() { //! // The object that we will serialize. -//! let target = Some("hello world".to_string()); -//! // The maximum size of the encoded message. -//! let limit = Bounded(20); +//! let target: Option = Some("hello world".to_string()); //! -//! let encoded: Vec = serialize(&target, limit).unwrap(); +//! let encoded: Vec = serialize(&target).unwrap(); //! let decoded: Option = deserialize(&encoded[..]).unwrap(); //! assert_eq!(target, decoded); //! } @@ -37,164 +25,121 @@ #![crate_type = "dylib"] extern crate byteorder; -extern crate serde as serde_crate; +extern crate serde; +mod config; mod ser; +mod error; mod de; -pub mod internal; +mod internal; -pub mod read { - //! The types that the deserializer uses for optimizations - pub use de::read::{SliceReader, BincodeRead, IoReader}; +pub use error::{Error, ErrorKind, Result}; +pub use config::Config; +pub use de::read::BincodeRead; + +/// 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. +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; } -use std::io::{Read, Write}; - -pub use internal::{ErrorKind, Error, Result, serialized_size, serialized_size_bounded}; - -/// A Deserializer that uses LittleEndian byteorder -pub type Deserializer = internal::Deserializer; -/// A Serializer that uses LittleEndian byteorder -pub type Serializer = internal::Serializer; - -/// Deserializes a slice of bytes into an object. +/// An object that implements this trait can be passed a +/// serde::Serializer without knowing its concrete type. /// -/// This method does not have a size-limit because if you already have the bytes -/// in memory, then you don't gain anything by having a limiter. -pub fn deserialize<'a, T>(bytes: &'a [u8]) -> internal::Result -where - T: serde_crate::de::Deserialize<'a>, -{ - internal::deserialize::<_, byteorder::LittleEndian>(bytes) +/// This trait should be used only for `with_serializer` functions. +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; } -/// Deserializes an object directly from a `Buffer`ed Reader. +/// Get a default configuration object. /// -/// If the provided `SizeLimit` is reached, the deserialization will bail immediately. -/// A SizeLimit can help prevent an attacker from flooding your server with -/// a neverending stream of values that runs your server out of memory. -/// -/// If this returns an `Error`, assume that the buffer that you passed -/// in is in an invalid state, as the error could be returned during any point -/// in the reading. -pub fn deserialize_from(reader: &mut R, size_limit: S) -> internal::Result -where - R: Read, - T: serde_crate::de::DeserializeOwned, - S: SizeLimit, -{ - internal::deserialize_from::<_, _, _, byteorder::LittleEndian>(reader, size_limit) +/// ### Default Configuration: +/// Byte limit: Unlimited +/// Endianness: Little +pub fn config() -> Config { + Config::new() } -/// Serializes an object directly into a `Writer`. +/// Serializes an object directly into a `Writer` using the default configuration. /// -/// If the serialization would take more bytes than allowed by `size_limit`, an error +/// 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`. -/// -/// If this returns an `Error` (other than SizeLimit), assume that the -/// writer is in an invalid state, as writing could bail out in the middle of -/// serializing. -pub fn serialize_into( - writer: &mut W, - value: &T, - size_limit: S, -) -> internal::Result<()> +pub fn serialize_into(writer: W, value: &T) -> Result<()> where - W: Write, - T: serde_crate::Serialize, - S: SizeLimit, + W: std::io::Write, + T: serde::Serialize, { - internal::serialize_into::<_, _, _, byteorder::LittleEndian>(writer, value, size_limit) + config().serialize_into(writer, value) } -/// Serializes a serializable object into a `Vec` of bytes. -/// -/// If the serialization would take more bytes than allowed by `size_limit`, -/// an error is returned. -pub fn serialize(value: &T, size_limit: S) -> internal::Result> +/// Serializes a serializable object into a `Vec` of bytes using the default configuration. +pub fn serialize(value: &T) -> Result> where - T: serde_crate::Serialize, - S: SizeLimit, + T: serde::Serialize, { - internal::serialize::<_, _, byteorder::LittleEndian>(value, size_limit) + config().serialize(value) } -/// A limit on the amount of bytes that can be read or written. +/// Deserializes an object directly from a `Read`er using the default configuration. /// -/// Size limits are an incredibly important part of both encoding and decoding. +/// If this returns an `Error`, `reader` may be in an invalid state. +pub fn deserialize_from(reader: R) -> Result +where + R: std::io::Read, + T: serde::de::DeserializeOwned, +{ + config().deserialize_from(reader) +} + +/// 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. /// -/// In order to prevent DOS attacks on a decoder, it is important to limit the -/// amount of bytes that a single encoded message can be; otherwise, if you -/// are decoding bytes right off of a TCP stream for example, it would be -/// possible for an attacker to flood your server with a 3TB vec, causing the -/// decoder to run out of memory and crash your application! -/// Because of this, you can provide a maximum-number-of-bytes that can be read -/// during decoding, and the decoder will explicitly fail if it has to read -/// any more than that. -/// -/// On the other side, you want to make sure that you aren't encoding a message -/// that is larger than your decoder expects. By supplying a size limit to an -/// encoding function, the encoder will verify that the structure can be encoded -/// within that limit. This verification occurs before any bytes are written to -/// the Writer, so recovering from an error is easy. -pub trait SizeLimit: private::Sealed { - /// 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; +/// If this returns an `Error`, `reader` may be in an invalid state. +pub fn deserialize_from_custom<'a, R, T>(reader: R) -> Result +where + R: de::read::BincodeRead<'a>, + T: serde::de::DeserializeOwned, +{ + config().deserialize_from_custom(reader) } -/// 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; - -struct CountSize { - total: u64, - limit: Option, +/// Deserializes a slice of bytes into an instance of `T` using the default configuration. +pub fn deserialize<'a, T>(bytes: &'a [u8]) -> Result +where + T: serde::de::Deserialize<'a>, +{ + config().deserialize(bytes) } -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) - } +/// Returns the size that an object would be if serialized using Bincode with the default configuration. +pub fn serialized_size(value: &T) -> Result +where + T: serde::Serialize, +{ + config().serialized_size(value) } -impl SizeLimit for Infinite { - #[inline(always)] - fn add(&mut self, _: u64) -> Result<()> { - Ok(()) - } - - #[inline(always)] - fn limit(&self) -> Option { - None - } +/// Executes the acceptor with a serde::Deserializer instance. +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) } -mod private { - pub trait Sealed {} - - impl<'a> Sealed for super::de::read::SliceReader<'a> {} - impl Sealed for super::de::read::IoReader {} - impl Sealed for super::Infinite {} - impl Sealed for super::Bounded {} - impl Sealed for super::CountSize {} +/// Executes the acceptor with a serde::Serializer instance. +pub fn with_serializer(writer: W, acceptor: A) -> A::Output +where A: SerializerAcceptor, + W: std::io::Write +{ + config().with_serializer(writer, acceptor) } diff --git a/src/ser/mod.rs b/src/ser/mod.rs index b08067a..f9dd26d 100644 --- a/src/ser/mod.rs +++ b/src/ser/mod.rs @@ -1,13 +1,13 @@ use std::io::Write; use std::u32; -use std::marker::PhantomData; -use serde_crate as serde; +use serde; -use byteorder::{WriteBytesExt, ByteOrder}; +use byteorder::WriteBytesExt; use super::{Result, Error, ErrorKind}; -use super::SizeLimit; +use ::config::Options; +use super::internal::SizeLimit; /// An Serializer that encodes values directly into a Writer. /// @@ -16,31 +16,31 @@ use super::SizeLimit; /// /// This struct should not be used often. /// For most cases, prefer the `encode_into` function. -pub struct Serializer { +pub(crate) struct Serializer { writer: W, - _phantom: PhantomData, + _options: O, } -impl Serializer { +impl Serializer { /// Creates a new Serializer with the given `Write`r. - pub fn new(w: W) -> Serializer { + pub fn new(w: W, options: O) -> Serializer { Serializer { writer: w, - _phantom: PhantomData, + _options: options, } } } -impl<'a, W: Write, E: ByteOrder> serde::Serializer for &'a mut Serializer { +impl<'a, W: Write, O: Options> serde::Serializer for &'a mut Serializer { type Ok = (); type Error = Error; - type SerializeSeq = Compound<'a, W, E>; - type SerializeTuple = Compound<'a, W, E>; - type SerializeTupleStruct = Compound<'a, W, E>; - type SerializeTupleVariant = Compound<'a, W, E>; - type SerializeMap = Compound<'a, W, E>; - type SerializeStruct = Compound<'a, W, E>; - type SerializeStructVariant = Compound<'a, W, E>; + type SerializeSeq = Compound<'a, W, O>; + type SerializeTuple = Compound<'a, W, O>; + type SerializeTupleStruct = Compound<'a, W, O>; + type SerializeTupleVariant = Compound<'a, W, O>; + type SerializeMap = Compound<'a, W, O>; + type SerializeStruct = Compound<'a, W, O>; + type SerializeStructVariant = Compound<'a, W, O>; fn serialize_unit(self) -> Result<()> { Ok(()) @@ -61,15 +61,15 @@ impl<'a, W: Write, E: ByteOrder> 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::(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::(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::(v).map_err(Into::into) } fn serialize_i8(self, v: i8) -> Result<()> { @@ -77,23 +77,23 @@ impl<'a, W: Write, E: ByteOrder> 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::(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::(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::(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::(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::(v).map_err(Into::into) } fn serialize_str(self, v: &str) -> Result<()> { @@ -209,17 +209,17 @@ impl<'a, W: Write, E: ByteOrder> serde::Serializer for &'a mut Serializer } } -pub struct SizeChecker { - pub size_limit: S, +pub(crate) struct SizeChecker { + pub options: O, } -impl SizeChecker { - pub fn new(size_limit: S) -> SizeChecker { - SizeChecker { size_limit: size_limit } +impl SizeChecker { + pub fn new(options: O) -> SizeChecker { + SizeChecker { options: options } } fn add_raw(&mut self, size: u64) -> Result<()> { - self.size_limit.add(size) + self.options.limit().add(size) } fn add_value(&mut self, t: T) -> Result<()> { @@ -228,16 +228,16 @@ impl SizeChecker { } } -impl<'a, S: SizeLimit> serde::Serializer for &'a mut SizeChecker { +impl<'a, O: Options> serde::Serializer for &'a mut SizeChecker { type Ok = (); type Error = Error; - type SerializeSeq = SizeCompound<'a, S>; - type SerializeTuple = SizeCompound<'a, S>; - type SerializeTupleStruct = SizeCompound<'a, S>; - type SerializeTupleVariant = SizeCompound<'a, S>; - type SerializeMap = SizeCompound<'a, S>; - type SerializeStruct = SizeCompound<'a, S>; - type SerializeStructVariant = SizeCompound<'a, S>; + type SerializeSeq = SizeCompound<'a, O>; + type SerializeTuple = SizeCompound<'a, O>; + type SerializeTupleStruct = SizeCompound<'a, O>; + type SerializeTupleVariant = SizeCompound<'a, O>; + type SerializeMap = SizeCompound<'a, O>; + type SerializeStruct = SizeCompound<'a, O>; + type SerializeStructVariant = SizeCompound<'a, O>; fn serialize_unit(self) -> Result<()> { Ok(()) @@ -402,15 +402,14 @@ impl<'a, S: SizeLimit> serde::Serializer for &'a mut SizeChecker { } } -#[doc(hidden)] -pub struct Compound<'a, W: 'a, E: ByteOrder + 'a> { - ser: &'a mut Serializer, +pub(crate) struct Compound<'a, W: 'a, O: Options + 'a> { + ser: &'a mut Serializer, } -impl<'a, W, E> serde::ser::SerializeSeq for Compound<'a, W, E> +impl<'a, W, O> serde::ser::SerializeSeq for Compound<'a, W, O> where W: Write, - E: ByteOrder, + O: Options, { type Ok = (); type Error = Error; @@ -429,10 +428,10 @@ where } } -impl<'a, W, E> serde::ser::SerializeTuple for Compound<'a, W, E> +impl<'a, W, O> serde::ser::SerializeTuple for Compound<'a, W, O> where W: Write, - E: ByteOrder, + O: Options, { type Ok = (); type Error = Error; @@ -451,10 +450,10 @@ where } } -impl<'a, W, E> serde::ser::SerializeTupleStruct for Compound<'a, W, E> +impl<'a, W, O> serde::ser::SerializeTupleStruct for Compound<'a, W, O> where W: Write, - E: ByteOrder, + O: Options, { type Ok = (); type Error = Error; @@ -473,10 +472,10 @@ where } } -impl<'a, W, E> serde::ser::SerializeTupleVariant for Compound<'a, W, E> +impl<'a, W, O> serde::ser::SerializeTupleVariant for Compound<'a, W, O> where W: Write, - E: ByteOrder, + O: Options, { type Ok = (); type Error = Error; @@ -495,10 +494,10 @@ where } } -impl<'a, W, E> serde::ser::SerializeMap for Compound<'a, W, E> +impl<'a, W, O> serde::ser::SerializeMap for Compound<'a, W, O> where W: Write, - E: ByteOrder, + O: Options, { type Ok = (); type Error = Error; @@ -525,10 +524,10 @@ where } } -impl<'a, W, E> serde::ser::SerializeStruct for Compound<'a, W, E> +impl<'a, W, O> serde::ser::SerializeStruct for Compound<'a, W, O> where W: Write, - E: ByteOrder, + O: Options, { type Ok = (); type Error = Error; @@ -547,10 +546,10 @@ where } } -impl<'a, W, E> serde::ser::SerializeStructVariant for Compound<'a, W, E> +impl<'a, W, O> serde::ser::SerializeStructVariant for Compound<'a, W, O> where W: Write, - E: ByteOrder, + O: Options, { type Ok = (); type Error = Error; @@ -569,12 +568,11 @@ where } } -#[doc(hidden)] -pub struct SizeCompound<'a, S: SizeLimit + 'a> { +pub(crate) struct SizeCompound<'a, S: Options + 'a> { ser: &'a mut SizeChecker, } -impl<'a, S: SizeLimit> serde::ser::SerializeSeq for SizeCompound<'a, S> { +impl<'a, O: Options> serde::ser::SerializeSeq for SizeCompound<'a, O> { type Ok = (); type Error = Error; @@ -592,7 +590,7 @@ impl<'a, S: SizeLimit> serde::ser::SerializeSeq for SizeCompound<'a, S> { } } -impl<'a, S: SizeLimit> serde::ser::SerializeTuple for SizeCompound<'a, S> { +impl<'a, O: Options> serde::ser::SerializeTuple for SizeCompound<'a, O> { type Ok = (); type Error = Error; @@ -610,7 +608,7 @@ impl<'a, S: SizeLimit> serde::ser::SerializeTuple for SizeCompound<'a, S> { } } -impl<'a, S: SizeLimit> serde::ser::SerializeTupleStruct for SizeCompound<'a, S> { +impl<'a, O: Options> serde::ser::SerializeTupleStruct for SizeCompound<'a, O> { type Ok = (); type Error = Error; @@ -628,7 +626,7 @@ impl<'a, S: SizeLimit> serde::ser::SerializeTupleStruct for SizeCompound<'a, S> } } -impl<'a, S: SizeLimit> serde::ser::SerializeTupleVariant for SizeCompound<'a, S> { +impl<'a, O: Options> serde::ser::SerializeTupleVariant for SizeCompound<'a, O> { type Ok = (); type Error = Error; @@ -646,7 +644,7 @@ impl<'a, S: SizeLimit> serde::ser::SerializeTupleVariant for SizeCompound<'a, S> } } -impl<'a, S: SizeLimit + 'a> serde::ser::SerializeMap for SizeCompound<'a, S> { +impl<'a, O: Options+ 'a> serde::ser::SerializeMap for SizeCompound<'a, O> { type Ok = (); type Error = Error; @@ -672,7 +670,7 @@ impl<'a, S: SizeLimit + 'a> serde::ser::SerializeMap for SizeCompound<'a, S> { } } -impl<'a, S: SizeLimit> serde::ser::SerializeStruct for SizeCompound<'a, S> { +impl<'a, O: Options> serde::ser::SerializeStruct for SizeCompound<'a, O> { type Ok = (); type Error = Error; @@ -690,7 +688,7 @@ impl<'a, S: SizeLimit> serde::ser::SerializeStruct for SizeCompound<'a, S> { } } -impl<'a, S: SizeLimit> serde::ser::SerializeStructVariant for SizeCompound<'a, S> { +impl<'a, O: Options> serde::ser::SerializeStructVariant for SizeCompound<'a, O> { type Ok = (); type Error = Error; diff --git a/tests/test.rs b/tests/test.rs index 79d8ca6..440be46 100644 --- a/tests/test.rs +++ b/tests/test.rs @@ -2,48 +2,43 @@ extern crate serde_derive; extern crate bincode; +extern crate byteorder; extern crate serde; extern crate serde_bytes; -extern crate byteorder; use std::fmt::Debug; use std::collections::HashMap; use std::borrow::Cow; -use bincode::{Bounded, Infinite}; -use bincode::{serialized_size, ErrorKind, Result}; -use bincode::internal::{deserialize, deserialize_from, serialize}; - -use bincode::serialize as serialize_little; -use bincode::deserialize as deserialize_little; -use bincode::deserialize_from as deserialize_from_little; +use bincode::{config, deserialize, deserialize_from, serialize, serialized_size, ErrorKind, Result}; fn the_same(element: V) where V: serde::Serialize + serde::de::DeserializeOwned + PartialEq + Debug + 'static, { - let size = serialized_size(&element); + let size = serialized_size(&element).unwrap(); { - let encoded = serialize_little(&element, Infinite).unwrap(); - let decoded = deserialize_little(&encoded[..]).unwrap(); + let encoded = serialize(&element).unwrap(); + let decoded = deserialize(&encoded[..]).unwrap(); assert_eq!(element, decoded); assert_eq!(size, encoded.len() as u64); } { - let encoded = serialize::<_, _, byteorder::BigEndian>(&element, Infinite).unwrap(); - let decoded = deserialize::<_, byteorder::BigEndian>(&encoded[..]).unwrap(); - let decoded_reader = - deserialize_from::<_, _, _, byteorder::BigEndian>(&mut &encoded[..], Infinite).unwrap(); + let encoded = config().big_endian().serialize(&element).unwrap(); + let decoded = config().big_endian().deserialize(&encoded[..]).unwrap(); + let decoded_reader = config() + .big_endian() + .deserialize_from(&mut &encoded[..]) + .unwrap(); assert_eq!(element, decoded); assert_eq!(element, decoded_reader); assert_eq!(size, encoded.len() as u64); } } - #[test] fn test_numbers() { // unsigned positive @@ -213,12 +208,11 @@ fn test_fixed_size_array() { #[test] fn deserializing_errors() { - - match *deserialize_little::(&vec![0xA][..]).unwrap_err() { + match *deserialize::(&vec![0xA][..]).unwrap_err() { ErrorKind::InvalidBoolEncoding(0xA) => {} _ => panic!(), } - match *deserialize_little::(&vec![1, 0, 0, 0, 0, 0, 0, 0, 0xFF][..]).unwrap_err() { + match *deserialize::(&vec![1, 0, 0, 0, 0, 0, 0, 0, 0xFF][..]).unwrap_err() { ErrorKind::InvalidUtf8Encoding(_) => {} _ => panic!(), } @@ -230,12 +224,12 @@ fn deserializing_errors() { Two, }; - match *deserialize_little::(&vec![0, 0, 0, 5][..]).unwrap_err() { + match *deserialize::(&vec![0, 0, 0, 5][..]).unwrap_err() { // Error message comes from serde ErrorKind::Custom(_) => {} _ => panic!(), } - match *deserialize_little::>(&vec![5, 0][..]).unwrap_err() { + match *deserialize::>(&vec![5, 0][..]).unwrap_err() { ErrorKind::InvalidTagEncoding(_) => {} _ => panic!(), } @@ -244,13 +238,11 @@ fn deserializing_errors() { #[test] fn too_big_deserialize() { let serialized = vec![0, 0, 0, 3]; - let deserialized: Result = - deserialize_from_little::<_, _, _>(&mut &serialized[..], Bounded(3)); + let deserialized: Result = config().limit(3).deserialize_from(&mut &serialized[..]); assert!(deserialized.is_err()); let serialized = vec![0, 0, 0, 3]; - let deserialized: Result = - deserialize_from_little::<_, _, _>(&mut &serialized[..], Bounded(4)); + let deserialized: Result = config().limit(4).deserialize_from(&mut &serialized[..]); assert!(deserialized.is_ok()); } @@ -258,8 +250,11 @@ fn too_big_deserialize() { fn char_serialization() { let chars = "Aa\0☺♪"; for c in chars.chars() { - let encoded = serialize_little(&c, Bounded(4)).expect("serializing char failed"); - let decoded: char = deserialize_little(&encoded).expect("deserializing failed"); + let encoded = config() + .limit(4) + .serialize(&c) + .expect("serializing char failed"); + let decoded: char = deserialize(&encoded).expect("deserializing failed"); assert_eq!(decoded, c); } } @@ -267,48 +262,60 @@ fn char_serialization() { #[test] fn too_big_char_deserialize() { let serialized = vec![0x41]; - let deserialized: Result = - deserialize_from_little::<_, _, _>(&mut &serialized[..], Bounded(1)); + let deserialized: Result = config().limit(1).deserialize_from(&mut &serialized[..]); assert!(deserialized.is_ok()); assert_eq!(deserialized.unwrap(), 'A'); } #[test] fn too_big_serialize() { - assert!(serialize_little(&0u32, Bounded(3)).is_err()); - assert!(serialize_little(&0u32, Bounded(4)).is_ok()); - - assert!(serialize_little(&"abcde", Bounded(8 + 4)).is_err()); - assert!(serialize_little(&"abcde", Bounded(8 + 5)).is_ok()); -} - -#[test] -fn test_proxy_encoded_size() { - assert!(serialized_size(&0u8) == 1); - assert!(serialized_size(&0u16) == 2); - assert!(serialized_size(&0u32) == 4); - assert!(serialized_size(&0u64) == 8); - - // length isize stored as u64 - assert!(serialized_size(&"") == 8); - assert!(serialized_size(&"a") == 8 + 1); - - assert!(serialized_size(&vec![0u32, 1u32, 2u32]) == 8 + 3 * (4)) + assert!(config().limit(3).serialize(&0u32).is_err()); + assert!(config().limit(4).serialize(&0u32).is_ok()); + assert!(config().limit(8 + 4).serialize(&"abcde").is_err()); + assert!(config().limit(8 + 5).serialize(&"abcde").is_ok()); } #[test] fn test_serialized_size() { - assert!(serialized_size(&0u8) == 1); - assert!(serialized_size(&0u16) == 2); - assert!(serialized_size(&0u32) == 4); - assert!(serialized_size(&0u64) == 8); + assert!(serialized_size(&0u8).unwrap() == 1); + assert!(serialized_size(&0u16).unwrap() == 2); + assert!(serialized_size(&0u32).unwrap() == 4); + assert!(serialized_size(&0u64).unwrap() == 8); // length isize stored as u64 - assert!(serialized_size(&"") == 8); - assert!(serialized_size(&"a") == 8 + 1); + assert!(serialized_size(&"").unwrap() == 8); + assert!(serialized_size(&"a").unwrap() == 8 + 1); - assert!(serialized_size(&vec![0u32, 1u32, 2u32]) == 8 + 3 * (4)) + assert!(serialized_size(&vec![0u32, 1u32, 2u32]).unwrap() == 8 + 3 * (4)); +} + +#[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) + .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) + .serialized_size(&vec![0u32, 1u32, 2u32]).is_err()); } #[test] @@ -331,10 +338,8 @@ fn test_cow_serialize() { // Test 1 { - let serialized = - serialize_little(&Message::M1(Cow::Borrowed(&large_object)), Infinite).unwrap(); - let deserialized: Message<'static> = - deserialize_from_little(&mut &serialized[..], Infinite).unwrap(); + let serialized = serialize(&Message::M1(Cow::Borrowed(&large_object))).unwrap(); + let deserialized: Message<'static> = deserialize_from(&mut &serialized[..]).unwrap(); match deserialized { Message::M1(b) => assert!(&b.into_owned() == &large_object), @@ -344,10 +349,8 @@ fn test_cow_serialize() { // Test 2 { - let serialized = - serialize_little(&Message::M2(Cow::Borrowed(&large_map)), Infinite).unwrap(); - let deserialized: Message<'static> = - deserialize_from_little(&mut &serialized[..], Infinite).unwrap(); + let serialized = serialize(&Message::M2(Cow::Borrowed(&large_map))).unwrap(); + let deserialized: Message<'static> = deserialize_from(&mut &serialized[..]).unwrap(); match deserialized { Message::M2(b) => assert!(&b.into_owned() == &large_map), @@ -359,9 +362,8 @@ fn test_cow_serialize() { #[test] fn test_strbox_serialize() { let strx: &'static str = "hello world"; - let serialized = serialize_little(&Cow::Borrowed(strx), Infinite).unwrap(); - let deserialized: Cow<'static, String> = - deserialize_from_little(&mut &serialized[..], Infinite).unwrap(); + let serialized = serialize(&Cow::Borrowed(strx)).unwrap(); + let deserialized: Cow<'static, String> = deserialize_from(&mut &serialized[..]).unwrap(); let stringx: String = deserialized.into_owned(); assert!(strx == &stringx[..]); } @@ -369,10 +371,9 @@ fn test_strbox_serialize() { #[test] fn test_slicebox_serialize() { let slice = [1u32, 2, 3, 4, 5]; - let serialized = serialize_little(&Cow::Borrowed(&slice[..]), Infinite).unwrap(); + let serialized = serialize(&Cow::Borrowed(&slice[..])).unwrap(); println!("{:?}", serialized); - let deserialized: Cow<'static, Vec> = - deserialize_from_little(&mut &serialized[..], Infinite).unwrap(); + let deserialized: Cow<'static, Vec> = deserialize_from(&mut &serialized[..]).unwrap(); { let sb: &[u32] = &deserialized; assert!(slice == sb); @@ -383,7 +384,7 @@ fn test_slicebox_serialize() { #[test] fn test_multi_strings_serialize() { - assert!(serialize_little(&("foo", "bar", "baz"), Infinite).is_ok()); + assert!(serialize(&("foo", "bar", "baz")).is_ok()); } #[test] @@ -394,14 +395,16 @@ fn test_oom_protection() { len: u64, byte: u8, } - let x = serialize_little( - &FakeVec { + let x = config() + .limit(10) + .serialize(&FakeVec { len: 0xffffffffffffffffu64, byte: 1, - }, - Bounded(10), - ).unwrap(); - let y: Result> = deserialize_from_little(&mut Cursor::new(&x[..]), Bounded(10)); + }) + .unwrap(); + let y: Result> = config() + .limit(10) + .deserialize_from(&mut Cursor::new(&x[..])); assert!(y.is_err()); } @@ -409,8 +412,8 @@ fn test_oom_protection() { fn path_buf() { use std::path::{Path, PathBuf}; let path = Path::new("foo").to_path_buf(); - let serde_encoded = serialize_little(&path, Infinite).unwrap(); - let decoded: PathBuf = deserialize_little(&serde_encoded).unwrap(); + let serde_encoded = serialize(&path).unwrap(); + let decoded: PathBuf = deserialize(&serde_encoded).unwrap(); assert!(path.to_str() == decoded.to_str()); } @@ -419,8 +422,8 @@ fn bytes() { use serde_bytes::Bytes; let data = b"abc\0123"; - let s = serialize_little(&data[..], Infinite).unwrap(); - let s2 = serialize_little(&Bytes::new(data), Infinite).unwrap(); + let s = serialize(&data[..]).unwrap(); + let s2 = serialize(&Bytes::new(data)).unwrap(); assert_eq!(s[..], s2[..]); } @@ -434,8 +437,8 @@ fn serde_bytes() { #[test] fn endian_difference() { let x = 10u64; - let little = serialize_little(&x, Infinite).unwrap(); - let big = serialize::<_, _, byteorder::BigEndian>(&x, Infinite).unwrap(); + let little = serialize(&x).unwrap(); + let big = config().big_endian().serialize(&x).unwrap(); assert_ne!(little, big); } @@ -452,8 +455,8 @@ fn test_zero_copy_parse() { borrowed_bytes: &[0, 1, 2, 3], }; { - let encoded = serialize_little(&f, Infinite).unwrap(); - let out: Foo = deserialize_little(&encoded[..]).unwrap(); + let encoded = serialize(&f).unwrap(); + let out: Foo = deserialize(&encoded[..]).unwrap(); assert_eq!(out, f); } } @@ -463,6 +466,6 @@ fn not_human_readable() { use std::net::Ipv4Addr; let ip = Ipv4Addr::new(1, 2, 3, 4); the_same(ip); - assert_eq!(&ip.octets()[..], &serialize_little(&ip, Infinite).unwrap()[..]); - assert_eq!(::std::mem::size_of::() as u64, serialized_size(&ip)); + assert_eq!(&ip.octets()[..], &serialize(&ip).unwrap()[..]); + assert_eq!(::std::mem::size_of::() as u64, serialized_size(&ip).unwrap()); }