use std::io::{Read, Write}; use self::EndianOption::*; use self::LimitOption::*; use super::{DefaultOptions, Options}; use de::read::BincodeRead; use error::Result; use serde; /// 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. #[derive(Clone, Debug)] #[deprecated( since = "1.3.0", note = "please use the `DefaultOptions`/`Options` system instead" )] pub struct Config { limit: LimitOption, endian: EndianOption, } #[derive(Clone, Copy, Debug)] enum LimitOption { Unlimited, Limited(u64), } #[derive(Clone, Copy, Debug)] enum EndianOption { Big, Little, Native, } macro_rules! config_map { ($self:expr, $opts:ident => $call:expr) => { match ($self.limit, $self.endian) { (Unlimited, Little) => { let $opts = DefaultOptions::new() .with_fixint_encoding() .allow_trailing_bytes() .with_no_limit() .with_little_endian(); $call } (Unlimited, Big) => { let $opts = DefaultOptions::new() .with_fixint_encoding() .allow_trailing_bytes() .with_no_limit() .with_big_endian(); $call } (Unlimited, Native) => { let $opts = DefaultOptions::new() .with_fixint_encoding() .allow_trailing_bytes() .with_no_limit() .with_native_endian(); $call } (Limited(l), Little) => { let $opts = DefaultOptions::new() .with_fixint_encoding() .allow_trailing_bytes() .with_limit(l) .with_little_endian(); $call } (Limited(l), Big) => { let $opts = DefaultOptions::new() .with_fixint_encoding() .allow_trailing_bytes() .with_limit(l) .with_big_endian(); $call } (Limited(l), Native) => { let $opts = DefaultOptions::new() .with_fixint_encoding() .allow_trailing_bytes() .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)) } /// TODO: document #[doc(hidden)] #[inline(always)] pub fn deserialize_in_place<'a, R, T>(&self, reader: R, place: &mut T) -> Result<()> where R: BincodeRead<'a>, T: serde::de::Deserialize<'a>, { config_map!(self, opts => ::internal::deserialize_in_place(reader, opts, place)) } /// Deserializes a slice of bytes with state `seed` using this configuration. #[inline(always)] pub fn deserialize_seed<'a, T: serde::de::DeserializeSeed<'a>>( &self, seed: T, bytes: &'a [u8], ) -> Result { config_map!(self, opts => ::internal::deserialize_seed(seed, 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 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)] pub fn deserialize_from_seed<'a, R: Read, T: serde::de::DeserializeSeed<'a>>( &self, seed: T, reader: R, ) -> Result { config_map!(self, opts => ::internal::deserialize_from_seed(seed, 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)) } /// 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)] pub fn deserialize_from_custom_seed< 'a, R: BincodeRead<'a>, T: serde::de::DeserializeSeed<'a>, >( &self, seed: T, reader: R, ) -> Result { config_map!(self, opts => ::internal::deserialize_from_custom_seed(seed, reader, opts)) } }