//! `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<Self, Infinite> { | |
WithOtherLimit::new(self, Infinite) | |
} | |
/// Sets the byte limit to `limit`. | |
fn with_limit(self, limit: u64) -> WithOtherLimit<Self, Bounded> { | |
WithOtherLimit::new(self, Bounded(limit)) | |
} | |
/// Sets the endianness to little-endian | |
/// This is the default. | |
fn with_little_endian(self) -> WithOtherEndian<Self, LittleEndian> { | |
WithOtherEndian::new(self) | |
} | |
/// Sets the endianness to big-endian | |
fn with_big_endian(self) -> WithOtherEndian<Self, BigEndian> { | |
WithOtherEndian::new(self) | |
} | |
/// Sets the endianness to the the machine-native endianness | |
fn with_native_endian(self) -> WithOtherEndian<Self, NativeEndian> { | |
WithOtherEndian::new(self) | |
} | |
/// Sets the length encoding to varint | |
fn with_varint_encoding(self) -> WithOtherIntEncoding<Self, VarintEncoding> { | |
WithOtherIntEncoding::new(self) | |
} | |
/// Sets the length encoding to be fixed | |
fn with_fixint_encoding(self) -> WithOtherIntEncoding<Self, FixintEncoding> { | |
WithOtherIntEncoding::new(self) | |
} | |
/// Sets the deserializer to reject trailing bytes | |
fn reject_trailing_bytes(self) -> WithOtherTrailing<Self, RejectTrailing> { | |
WithOtherTrailing::new(self) | |
} | |
/// Sets the deserializer to allow trailing bytes | |
fn allow_trailing_bytes(self) -> WithOtherTrailing<Self, AllowTrailing> { | |
WithOtherTrailing::new(self) | |
} | |
/// Serializes a serializable object into a `Vec` of bytes using this configuration | |
#[inline(always)] | |
fn serialize<S: ?Sized + serde::Serialize>(self, t: &S) -> Result<Vec<u8>> { | |
::internal::serialize(t, self) | |
} | |
/// Returns the size that an object would be if serialized using Bincode with this configuration | |
#[inline(always)] | |
fn serialized_size<T: ?Sized + serde::Serialize>(self, t: &T) -> Result<u64> { | |
::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<W: Write, T: ?Sized + serde::Serialize>(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<T> { | |
::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<T::Value> { | |
::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<R: Read, T: serde::de::DeserializeOwned>(self, reader: R) -> Result<T> { | |
::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<T::Value> { | |
::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<T> { | |
::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<T::Value> { | |
::internal::deserialize_from_custom_seed(seed, reader, self) | |
} | |
} | |
impl<T: InternalOptions> Options for T {} | |
/// A configuration struct with a user-specified byte limit | |
#[derive(Clone, Copy)] | |
pub struct WithOtherLimit<O: Options, L: SizeLimit> { | |
_options: O, | |
pub(crate) new_limit: L, | |
} | |
/// A configuration struct with a user-specified endian order | |
#[derive(Clone, Copy)] | |
pub struct WithOtherEndian<O: Options, E: BincodeByteOrder> { | |
options: O, | |
_endian: PhantomData<E>, | |
} | |
/// A configuration struct with a user-specified length encoding | |
#[derive(Clone, Copy)] | |
pub struct WithOtherIntEncoding<O: Options, I: IntEncoding> { | |
options: O, | |
_length: PhantomData<I>, | |
} | |
/// A configuration struct with a user-specified trailing bytes behavior. | |
#[derive(Clone, Copy)] | |
pub struct WithOtherTrailing<O: Options, T: TrailingBytes> { | |
options: O, | |
_trailing: PhantomData<T>, | |
} | |
impl<O: Options, L: SizeLimit> WithOtherLimit<O, L> { | |
#[inline(always)] | |
pub(crate) fn new(options: O, limit: L) -> WithOtherLimit<O, L> { | |
WithOtherLimit { | |
_options: options, | |
new_limit: limit, | |
} | |
} | |
} | |
impl<O: Options, E: BincodeByteOrder> WithOtherEndian<O, E> { | |
#[inline(always)] | |
pub(crate) fn new(options: O) -> WithOtherEndian<O, E> { | |
WithOtherEndian { | |
options, | |
_endian: PhantomData, | |
} | |
} | |
} | |
impl<O: Options, I: IntEncoding> WithOtherIntEncoding<O, I> { | |
#[inline(always)] | |
pub(crate) fn new(options: O) -> WithOtherIntEncoding<O, I> { | |
WithOtherIntEncoding { | |
options, | |
_length: PhantomData, | |
} | |
} | |
} | |
impl<O: Options, T: TrailingBytes> WithOtherTrailing<O, T> { | |
#[inline(always)] | |
pub(crate) fn new(options: O) -> WithOtherTrailing<O, T> { | |
WithOtherTrailing { | |
options, | |
_trailing: PhantomData, | |
} | |
} | |
} | |
impl<O: Options, E: BincodeByteOrder + 'static> InternalOptions for WithOtherEndian<O, E> { | |
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<O: Options, L: SizeLimit + 'static> InternalOptions for WithOtherLimit<O, L> { | |
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<O: Options, I: IntEncoding + 'static> InternalOptions for WithOtherIntEncoding<O, I> { | |
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<O: Options, T: TrailingBytes + 'static> InternalOptions for WithOtherTrailing<O, T> { | |
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() | |
} | |
} | |
} |