aboutsummaryrefslogtreecommitdiff
path: root/src/config/mod.rs
diff options
context:
space:
mode:
Diffstat (limited to 'src/config/mod.rs')
-rw-r--r--src/config/mod.rs408
1 files changed, 408 insertions, 0 deletions
diff --git a/src/config/mod.rs b/src/config/mod.rs
new file mode 100644
index 0000000..33fa920
--- /dev/null
+++ b/src/config/mod.rs
@@ -0,0 +1,408 @@
+//! `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()
+ }
+ }
+}