//! `bincode` uses a Builder-pattern to configure the Serializers and Deserializers in this //! crate. This means that if you need to customize the behavior of `bincode`, you should create an //! instance of the `DefaultOptions` struct: //! //! ```rust //! use bincode::Options; //! let my_options = bincode::DefaultOptions::new(); //! ``` //! //! # Options Struct vs bincode functions //! //! Due to historical reasons, the default options used by the `serialize()` and `deserialize()` //! family of functions are different than the default options created by the `DefaultOptions` struct: //! //! | | Byte limit | Endianness | Int Encoding | Trailing Behavior | //! |----------|------------|------------|--------------|-------------------| //! | struct | Unlimited | Little | Varint | Reject | //! | function | Unlimited | Little | Fixint | Allow | //! //! This means that if you want to use the `Serialize` / `Deserialize` structs with the same //! settings as the functions, you should adjust the `DefaultOptions` struct like so: //! //! ```rust //! use bincode::Options; //! let my_options = bincode::DefaultOptions::new() //! .with_fixint_encoding() //! .allow_trailing_bytes(); //! ``` use de::read::BincodeRead; use error::Result; use serde; use std::io::{Read, Write}; use std::marker::PhantomData; pub(crate) use self::endian::BincodeByteOrder; pub(crate) use self::int::IntEncoding; pub(crate) use self::internal::*; pub(crate) use self::limit::SizeLimit; pub(crate) use self::trailing::TrailingBytes; pub use self::endian::{BigEndian, LittleEndian, NativeEndian}; pub use self::int::{FixintEncoding, VarintEncoding}; pub use self::legacy::*; pub use self::limit::{Bounded, Infinite}; pub use self::trailing::{AllowTrailing, RejectTrailing}; mod endian; mod int; mod legacy; mod limit; mod trailing; /// The default options for bincode serialization/deserialization. /// /// ### Defaults /// By default bincode will use little-endian encoding for multi-byte integers, and will not /// limit the number of serialized/deserialized bytes. /// /// ### Configuring `DefaultOptions` /// /// `DefaultOptions` implements the [Options] trait, which means it exposes functions to change the behavior of bincode. /// /// For example, if you wanted to limit the bincode deserializer to 1 kilobyte of user input: /// /// ```rust /// use bincode::Options; /// let my_options = bincode::DefaultOptions::new().with_limit(1024); /// ``` /// /// ### DefaultOptions struct vs. functions /// /// The default configuration used by this struct is not the same as that used by the bincode /// helper functions in the root of this crate. See the /// [config](index.html#options-struct-vs-bincode-functions) module for more details #[derive(Copy, Clone)] pub struct DefaultOptions(Infinite); impl DefaultOptions { /// Get a default configuration object. /// /// ### Default Configuration: /// /// | Byte limit | Endianness | Int Encoding | Trailing Behavior | /// |------------|------------|--------------|-------------------| /// | Unlimited | Little | Varint | Reject | pub fn new() -> DefaultOptions { DefaultOptions(Infinite) } } impl Default for DefaultOptions { fn default() -> Self { Self::new() } } impl InternalOptions for DefaultOptions { type Limit = Infinite; type Endian = LittleEndian; type IntEncoding = VarintEncoding; type Trailing = RejectTrailing; #[inline(always)] fn limit(&mut self) -> &mut Infinite { &mut self.0 } } /// 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* /// /// Int Encoding: The encoding used for numbers, enum discriminants, and lengths. *default: varint* /// /// Trailing Behavior: The behavior when there are trailing bytes left over in a slice after deserialization. *default: reject* /// /// ### 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 trait Options: InternalOptions + 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) } /// Sets the length encoding to varint fn with_varint_encoding(self) -> WithOtherIntEncoding { WithOtherIntEncoding::new(self) } /// Sets the length encoding to be fixed fn with_fixint_encoding(self) -> WithOtherIntEncoding { WithOtherIntEncoding::new(self) } /// Sets the deserializer to reject trailing bytes fn reject_trailing_bytes(self) -> WithOtherTrailing { WithOtherTrailing::new(self) } /// Sets the deserializer to allow trailing bytes fn allow_trailing_bytes(self) -> WithOtherTrailing { WithOtherTrailing::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 Options for T {} /// A configuration struct with a user-specified byte limit #[derive(Clone, Copy)] pub struct WithOtherLimit { _options: O, pub(crate) new_limit: L, } /// A configuration struct with a user-specified endian order #[derive(Clone, Copy)] pub struct WithOtherEndian { options: O, _endian: PhantomData, } /// A configuration struct with a user-specified length encoding #[derive(Clone, Copy)] pub struct WithOtherIntEncoding { options: O, _length: PhantomData, } /// A configuration struct with a user-specified trailing bytes behavior. #[derive(Clone, Copy)] pub struct WithOtherTrailing { options: O, _trailing: 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, _endian: PhantomData, } } } impl WithOtherIntEncoding { #[inline(always)] pub(crate) fn new(options: O) -> WithOtherIntEncoding { WithOtherIntEncoding { options, _length: PhantomData, } } } impl WithOtherTrailing { #[inline(always)] pub(crate) fn new(options: O) -> WithOtherTrailing { WithOtherTrailing { options, _trailing: PhantomData, } } } impl InternalOptions for WithOtherEndian { type Limit = O::Limit; type Endian = E; type IntEncoding = O::IntEncoding; type Trailing = O::Trailing; #[inline(always)] fn limit(&mut self) -> &mut O::Limit { self.options.limit() } } impl InternalOptions for WithOtherLimit { type Limit = L; type Endian = O::Endian; type IntEncoding = O::IntEncoding; type Trailing = O::Trailing; fn limit(&mut self) -> &mut L { &mut self.new_limit } } impl InternalOptions for WithOtherIntEncoding { type Limit = O::Limit; type Endian = O::Endian; type IntEncoding = I; type Trailing = O::Trailing; fn limit(&mut self) -> &mut O::Limit { self.options.limit() } } impl InternalOptions for WithOtherTrailing { type Limit = O::Limit; type Endian = O::Endian; type IntEncoding = O::IntEncoding; type Trailing = T; fn limit(&mut self) -> &mut O::Limit { self.options.limit() } } mod internal { use super::*; pub trait InternalOptions { type Limit: SizeLimit + 'static; type Endian: BincodeByteOrder + 'static; type IntEncoding: IntEncoding + 'static; type Trailing: TrailingBytes + 'static; fn limit(&mut self) -> &mut Self::Limit; } impl<'a, O: InternalOptions> InternalOptions for &'a mut O { type Limit = O::Limit; type Endian = O::Endian; type IntEncoding = O::IntEncoding; type Trailing = O::Trailing; #[inline(always)] fn limit(&mut self) -> &mut Self::Limit { (*self).limit() } } }