Skip to main content

float_pigment_consistent_bincode/config/
mod.rs

1//! `bincode` uses a Builder-pattern to configure the Serializers and Deserializers in this
2//! crate. This means that if you need to customize the behavior of `bincode`, you should create an
3//! instance of the `DefaultOptions` struct:
4//!
5//! ```rust
6//! use float_pigment_consistent_bincode::Options;
7//! let my_options = float_pigment_consistent_bincode::DefaultOptions::new();
8//! ```
9//!
10//! # Options Struct vs bincode functions
11//!
12//! Due to historical reasons, the default options used by the `serialize()` and `deserialize()`
13//! family of functions are different than the default options created by the `DefaultOptions` struct:
14//!
15//! |          | Byte limit | Endianness | Int Encoding | Trailing Behavior |
16//! |----------|------------|------------|--------------|-------------------|
17//! | struct   | Unlimited  | Little     | Varint       | Reject            |
18//! | function | Unlimited  | Little     | Fixint       | Allow             |
19//!
20//! This means that if you want to use the `Serialize` / `Deserialize` structs with the same
21//! settings as the functions, you should adjust the `DefaultOptions` struct like so:
22//!
23//! ```rust
24//! use float_pigment_consistent_bincode::Options;
25//! let my_options = float_pigment_consistent_bincode::DefaultOptions::new()
26//!     .with_fixint_encoding()
27//!     .allow_trailing_bytes();
28//! ```
29
30use crate::de::read::BincodeRead;
31use crate::error::Result;
32use crate::io::{Read, Write};
33use alloc::vec::Vec;
34use core::marker::PhantomData;
35
36pub(crate) use self::endian::BincodeByteOrder;
37pub(crate) use self::int::IntEncoding;
38pub(crate) use self::internal::*;
39pub(crate) use self::limit::SizeLimit;
40pub(crate) use self::trailing::TrailingBytes;
41
42pub use self::endian::{BigEndian, LittleEndian, NativeEndian};
43pub use self::int::{FixintEncoding, VarintEncoding};
44pub use self::limit::{Bounded, Infinite};
45pub use self::trailing::{AllowTrailing, RejectTrailing};
46
47mod endian;
48mod int;
49mod limit;
50mod trailing;
51
52/// The default options for bincode serialization/deserialization.
53///
54/// ### Defaults
55/// By default bincode will use little-endian encoding for multi-byte integers, and will not
56/// limit the number of serialized/deserialized bytes.
57///
58/// ### Configuring `DefaultOptions`
59///
60/// `DefaultOptions` implements the [Options] trait, which means it exposes functions to change the behavior of bincode.
61///
62/// For example, if you wanted to limit the bincode deserializer to 1 kilobyte of user input:
63///
64/// ```rust
65/// use float_pigment_consistent_bincode::Options;
66/// let my_options = float_pigment_consistent_bincode::DefaultOptions::new().with_limit(1024);
67/// ```
68///
69/// ### DefaultOptions struct vs. functions
70///
71/// The default configuration used by this struct is not the same as that used by the bincode
72/// helper functions in the root of this crate. See the
73/// [config](index.html#options-struct-vs-bincode-functions) module for more details
74#[derive(Copy, Clone)]
75pub struct DefaultOptions(Infinite);
76
77/// Size detail for serialization
78pub struct SizeDetail(Vec<u32>);
79
80impl DefaultOptions {
81    /// Get a default configuration object.
82    ///
83    /// ### Default Configuration:
84    ///
85    /// | Byte limit | Endianness | Int Encoding | Trailing Behavior |
86    /// |------------|------------|--------------|-------------------|
87    /// | Unlimited  | Little     | Varint       | Reject            |
88    pub fn new() -> DefaultOptions {
89        DefaultOptions(Infinite)
90    }
91}
92
93impl Default for DefaultOptions {
94    fn default() -> Self {
95        Self::new()
96    }
97}
98
99impl InternalOptions for DefaultOptions {
100    type Limit = Infinite;
101    type Endian = LittleEndian;
102    type IntEncoding = VarintEncoding;
103    type Trailing = RejectTrailing;
104
105    #[inline(always)]
106    fn limit(&mut self) -> &mut Infinite {
107        &mut self.0
108    }
109}
110
111/// A configuration builder trait whose options Bincode will use
112/// while serializing and deserializing.
113///
114/// ### Options
115/// Endianness: The endianness with which multi-byte integers will be read/written.  *default: little endian*
116///
117/// Limit: The maximum number of bytes that will be read/written in a bincode serialize/deserialize. *default: unlimited*
118///
119/// Int Encoding: The encoding used for numbers, enum discriminants, and lengths. *default: varint*
120///
121/// Trailing Behavior: The behavior when there are trailing bytes left over in a slice after deserialization. *default: reject*
122///
123/// ### Byte Limit Details
124/// The purpose of byte-limiting is to prevent Denial-Of-Service attacks whereby malicious attackers get bincode
125/// deserialization to crash your process by allocating too much memory or keeping a connection open for too long.
126///
127/// When a byte limit is set, bincode will return `Err` on any deserialization that goes over the limit, or any
128/// serialization that goes over the limit.
129pub trait Options: InternalOptions + Sized {
130    /// Sets the byte limit to be unlimited.
131    /// This is the default.
132    fn with_no_limit(self) -> WithOtherLimit<Self, Infinite> {
133        WithOtherLimit::new(self, Infinite)
134    }
135
136    /// Sets the byte limit to `limit`.
137    fn with_limit(self, limit: u64) -> WithOtherLimit<Self, Bounded> {
138        WithOtherLimit::new(self, Bounded(limit))
139    }
140
141    /// Sets the endianness to little-endian
142    /// This is the default.
143    fn with_little_endian(self) -> WithOtherEndian<Self, LittleEndian> {
144        WithOtherEndian::new(self)
145    }
146
147    /// Sets the endianness to big-endian
148    fn with_big_endian(self) -> WithOtherEndian<Self, BigEndian> {
149        WithOtherEndian::new(self)
150    }
151
152    /// Sets the endianness to the the machine-native endianness
153    fn with_native_endian(self) -> WithOtherEndian<Self, NativeEndian> {
154        WithOtherEndian::new(self)
155    }
156
157    /// Sets the length encoding to varint
158    fn with_varint_encoding(self) -> WithOtherIntEncoding<Self, VarintEncoding> {
159        WithOtherIntEncoding::new(self)
160    }
161
162    /// Sets the length encoding to be fixed
163    fn with_fixint_encoding(self) -> WithOtherIntEncoding<Self, FixintEncoding> {
164        WithOtherIntEncoding::new(self)
165    }
166
167    /// Sets the deserializer to reject trailing bytes
168    fn reject_trailing_bytes(self) -> WithOtherTrailing<Self, RejectTrailing> {
169        WithOtherTrailing::new(self)
170    }
171
172    /// Sets the deserializer to allow trailing bytes
173    fn allow_trailing_bytes(self) -> WithOtherTrailing<Self, AllowTrailing> {
174        WithOtherTrailing::new(self)
175    }
176
177    /// Serializes a serializable object into a `Vec` of bytes using this configuration
178    #[inline(always)]
179    fn serialize<S: ?Sized + serde::Serialize>(self, t: &S) -> Result<Vec<u8>> {
180        crate::internal::serialize(t, self)
181    }
182
183    /// Returns the size that an object would be if serialized using Bincode with this configuration
184    #[inline(always)]
185    fn serialized_size<T: ?Sized + serde::Serialize>(self, t: &T) -> Result<(u64, SizeDetail)> {
186        crate::internal::serialized_size(t, self).map(|(s, sizes_list)| (s, SizeDetail(sizes_list)))
187    }
188
189    /// Serializes an object directly into a `Writer` using this configuration
190    ///
191    /// If the serialization would take more bytes than allowed by the size limit, an error
192    /// is returned and *no bytes* will be written into the `Writer`
193    #[inline(always)]
194    fn serialize_into<W: Write, T: ?Sized + serde::Serialize>(
195        self,
196        w: W,
197        t: &T,
198        d: SizeDetail,
199    ) -> Result<()> {
200        crate::internal::serialize_into(w, t, self, d.0)
201    }
202
203    /// Deserializes a slice of bytes into an instance of `T` using this configuration
204    #[inline(always)]
205    fn deserialize<'a, T: serde::Deserialize<'a>>(self, bytes: &'a [u8]) -> Result<T> {
206        crate::internal::deserialize(bytes, self)
207    }
208
209    /// TODO: document
210    #[doc(hidden)]
211    #[inline(always)]
212    fn deserialize_in_place<'a, R, T>(self, reader: R, place: &mut T) -> Result<()>
213    where
214        R: BincodeRead<'a>,
215        T: serde::de::Deserialize<'a>,
216    {
217        crate::internal::deserialize_in_place(reader, self, place)
218    }
219
220    /// Deserializes a slice of bytes with state `seed` using this configuration.
221    #[inline(always)]
222    fn deserialize_seed<'a, T: serde::de::DeserializeSeed<'a>>(
223        self,
224        seed: T,
225        bytes: &'a [u8],
226    ) -> Result<T::Value> {
227        crate::internal::deserialize_seed(seed, bytes, self)
228    }
229
230    /// Deserializes an object directly from a `Read`er using this configuration
231    ///
232    /// If this returns an `Error`, `reader` may be in an invalid state.
233    #[inline(always)]
234    fn deserialize_from<R: Read, T: serde::de::DeserializeOwned>(self, reader: R) -> Result<T> {
235        crate::internal::deserialize_from(reader, self)
236    }
237
238    /// Deserializes an object directly from a `Read`er with state `seed` using this configuration
239    ///
240    /// If this returns an `Error`, `reader` may be in an invalid state.
241    #[inline(always)]
242    fn deserialize_from_seed<'a, R: Read, T: serde::de::DeserializeSeed<'a>>(
243        self,
244        seed: T,
245        reader: R,
246    ) -> Result<T::Value> {
247        crate::internal::deserialize_from_seed(seed, reader, self)
248    }
249
250    /// Deserializes an object from a custom `BincodeRead`er using the default configuration.
251    /// It is highly recommended to use `deserialize_from` unless you need to implement
252    /// `BincodeRead` for performance reasons.
253    ///
254    /// If this returns an `Error`, `reader` may be in an invalid state.
255    #[inline(always)]
256    fn deserialize_from_custom<'a, R: BincodeRead<'a>, T: serde::de::DeserializeOwned>(
257        self,
258        reader: R,
259    ) -> Result<T> {
260        crate::internal::deserialize_from_custom(reader, self)
261    }
262
263    /// Deserializes an object from a custom `BincodeRead`er with state `seed` using the default
264    /// configuration. It is highly recommended to use `deserialize_from` unless you need to
265    /// implement `BincodeRead` for performance reasons.
266    ///
267    /// If this returns an `Error`, `reader` may be in an invalid state.
268    #[inline(always)]
269    fn deserialize_from_custom_seed<'a, R: BincodeRead<'a>, T: serde::de::DeserializeSeed<'a>>(
270        self,
271        seed: T,
272        reader: R,
273    ) -> Result<T::Value> {
274        crate::internal::deserialize_from_custom_seed(seed, reader, self)
275    }
276}
277
278impl<T: InternalOptions> Options for T {}
279
280/// A configuration struct with a user-specified byte limit
281#[derive(Clone, Copy)]
282pub struct WithOtherLimit<O: Options, L: SizeLimit> {
283    _options: O,
284    pub(crate) new_limit: L,
285}
286
287/// A configuration struct with a user-specified endian order
288#[derive(Clone, Copy)]
289pub struct WithOtherEndian<O: Options, E: BincodeByteOrder> {
290    options: O,
291    _endian: PhantomData<E>,
292}
293
294/// A configuration struct with a user-specified length encoding
295#[derive(Clone, Copy)]
296pub struct WithOtherIntEncoding<O: Options, I: IntEncoding> {
297    options: O,
298    _length: PhantomData<I>,
299}
300
301/// A configuration struct with a user-specified trailing bytes behavior.
302#[derive(Clone, Copy)]
303pub struct WithOtherTrailing<O: Options, T: TrailingBytes> {
304    options: O,
305    _trailing: PhantomData<T>,
306}
307
308impl<O: Options, L: SizeLimit> WithOtherLimit<O, L> {
309    #[inline(always)]
310    pub(crate) fn new(options: O, limit: L) -> WithOtherLimit<O, L> {
311        WithOtherLimit {
312            _options: options,
313            new_limit: limit,
314        }
315    }
316}
317
318impl<O: Options, E: BincodeByteOrder> WithOtherEndian<O, E> {
319    #[inline(always)]
320    pub(crate) fn new(options: O) -> WithOtherEndian<O, E> {
321        WithOtherEndian {
322            options,
323            _endian: PhantomData,
324        }
325    }
326}
327
328impl<O: Options, I: IntEncoding> WithOtherIntEncoding<O, I> {
329    #[inline(always)]
330    pub(crate) fn new(options: O) -> WithOtherIntEncoding<O, I> {
331        WithOtherIntEncoding {
332            options,
333            _length: PhantomData,
334        }
335    }
336}
337
338impl<O: Options, T: TrailingBytes> WithOtherTrailing<O, T> {
339    #[inline(always)]
340    pub(crate) fn new(options: O) -> WithOtherTrailing<O, T> {
341        WithOtherTrailing {
342            options,
343            _trailing: PhantomData,
344        }
345    }
346}
347
348impl<O: Options, E: BincodeByteOrder + 'static> InternalOptions for WithOtherEndian<O, E> {
349    type Limit = O::Limit;
350    type Endian = E;
351    type IntEncoding = O::IntEncoding;
352    type Trailing = O::Trailing;
353    #[inline(always)]
354    fn limit(&mut self) -> &mut O::Limit {
355        self.options.limit()
356    }
357}
358
359impl<O: Options, L: SizeLimit + 'static> InternalOptions for WithOtherLimit<O, L> {
360    type Limit = L;
361    type Endian = O::Endian;
362    type IntEncoding = O::IntEncoding;
363    type Trailing = O::Trailing;
364    fn limit(&mut self) -> &mut L {
365        &mut self.new_limit
366    }
367}
368
369impl<O: Options, I: IntEncoding + 'static> InternalOptions for WithOtherIntEncoding<O, I> {
370    type Limit = O::Limit;
371    type Endian = O::Endian;
372    type IntEncoding = I;
373    type Trailing = O::Trailing;
374
375    fn limit(&mut self) -> &mut O::Limit {
376        self.options.limit()
377    }
378}
379
380impl<O: Options, T: TrailingBytes + 'static> InternalOptions for WithOtherTrailing<O, T> {
381    type Limit = O::Limit;
382    type Endian = O::Endian;
383    type IntEncoding = O::IntEncoding;
384    type Trailing = T;
385
386    fn limit(&mut self) -> &mut O::Limit {
387        self.options.limit()
388    }
389}
390
391mod internal {
392    use super::*;
393
394    pub trait InternalOptions {
395        type Limit: SizeLimit + 'static;
396        type Endian: BincodeByteOrder + 'static;
397        type IntEncoding: IntEncoding + 'static;
398        type Trailing: TrailingBytes + 'static;
399
400        fn limit(&mut self) -> &mut Self::Limit;
401    }
402
403    impl<'a, O: InternalOptions> InternalOptions for &'a mut O {
404        type Limit = O::Limit;
405        type Endian = O::Endian;
406        type IntEncoding = O::IntEncoding;
407        type Trailing = O::Trailing;
408
409        #[inline(always)]
410        fn limit(&mut self) -> &mut Self::Limit {
411            (*self).limit()
412        }
413    }
414}