bincode2/
config.rs

1use super::internal::{Bounded, Infinite, SizeLimit, SizeType, U16, U32, U64, U8};
2use byteorder::{BigEndian, ByteOrder, LittleEndian, NativeEndian};
3use de::read::BincodeRead;
4use error::Result;
5use serde;
6use std::io::{Read, Write};
7use std::marker::PhantomData;
8use {DeserializerAcceptor, SerializerAcceptor};
9
10struct DefaultOptions(Infinite);
11
12pub(crate) trait Options {
13    type Limit: SizeLimit + 'static;
14    type Endian: ByteOrder + 'static;
15    type StringSize: SizeType + 'static;
16    type ArraySize: SizeType + 'static;
17
18    fn limit(&mut self) -> &mut Self::Limit;
19}
20
21pub(crate) trait OptionsExt: Options + Sized {
22    fn with_no_limit(self) -> WithOtherLimit<Self, Infinite> {
23        WithOtherLimit::new(self, Infinite)
24    }
25
26    fn with_limit(self, limit: u64) -> WithOtherLimit<Self, Bounded> {
27        WithOtherLimit::new(self, Bounded(limit))
28    }
29
30    fn with_little_endian(self) -> WithOtherEndian<Self, LittleEndian> {
31        WithOtherEndian::new(self)
32    }
33
34    fn with_big_endian(self) -> WithOtherEndian<Self, BigEndian> {
35        WithOtherEndian::new(self)
36    }
37
38    fn with_native_endian(self) -> WithOtherEndian<Self, NativeEndian> {
39        WithOtherEndian::new(self)
40    }
41
42    fn with_string_size<S>(self) -> WithOtherStringLength<Self, S>
43    where
44        S: SizeType,
45    {
46        WithOtherStringLength::new(self)
47    }
48
49    fn with_array_size<S>(self) -> WithOtherArrayLength<Self, S>
50    where
51        S: SizeType,
52    {
53        WithOtherArrayLength::new(self)
54    }
55}
56
57impl<'a, O: Options> Options for &'a mut O {
58    type Limit = O::Limit;
59    type Endian = O::Endian;
60    type StringSize = O::StringSize;
61    type ArraySize = O::ArraySize;
62
63    #[inline(always)]
64    fn limit(&mut self) -> &mut Self::Limit {
65        (*self).limit()
66    }
67}
68
69impl<T: Options> OptionsExt for T {}
70
71impl DefaultOptions {
72    fn new() -> DefaultOptions {
73        DefaultOptions(Infinite)
74    }
75}
76
77impl Options for DefaultOptions {
78    type Limit = Infinite;
79    type Endian = LittleEndian;
80    type StringSize = U64;
81    type ArraySize = U64;
82
83    #[inline(always)]
84    fn limit(&mut self) -> &mut Infinite {
85        &mut self.0
86    }
87}
88
89#[derive(Clone, Copy, Debug)]
90enum LimitOption {
91    Unlimited,
92    Limited(u64),
93}
94
95#[derive(Clone, Copy, Debug)]
96enum EndianOption {
97    Big,
98    Little,
99    Native,
100}
101
102/// Used to specify the unit used for length of strings and arrays via `config.string_length` or `config.array_length`.
103#[derive(Clone, Copy, Debug)]
104pub enum LengthOption {
105    ///64 unsigned bits
106    U64,
107    ///32 unsigned bits
108    U32,
109    ///16 unsigned bits
110    U16,
111    ///8 unsigned bits
112    U8,
113}
114
115/// A configuration builder whose options Bincode will use
116/// while serializing and deserializing.
117///
118/// ### Options
119/// Endianness: The endianness with which multi-byte integers will be read/written.  *default: little endian*
120/// Limit: The maximum number of bytes that will be read/written in a bincode serialize/deserialize. *default: unlimited*
121///
122/// ### Byte Limit Details
123/// The purpose of byte-limiting is to prevent Denial-Of-Service attacks whereby malicious attackers get bincode
124/// deserialization to crash your process by allocating too much memory or keeping a connection open for too long.
125///
126/// When a byte limit is set, bincode will return `Err` on any deserialization that goes over the limit, or any
127/// serialization that goes over the limit.
128///
129/// ### Array and String sizes
130/// When writing a string or an array is serialized the length is written at the beginning so that the data
131/// can be deserialized. The option is a way to configure how this length is encoded. The default for both
132/// is `U64`.
133///
134/// If a string or array is attempted to be serialized that is not fit within the type specified bincode will return `Err`
135/// on serialization.
136#[derive(Clone, Debug)]
137pub struct Config {
138    limit: LimitOption,
139    endian: EndianOption,
140    string_size: LengthOption,
141    array_size: LengthOption,
142}
143
144pub(crate) struct WithOtherLimit<O: Options, L: SizeLimit> {
145    _options: O,
146    pub(crate) new_limit: L,
147}
148
149pub(crate) struct WithOtherEndian<O: Options, E: ByteOrder> {
150    options: O,
151    _endian: PhantomData<E>,
152}
153
154pub(crate) struct WithOtherStringLength<O: Options, L: SizeType> {
155    options: O,
156    _new_string_length: PhantomData<L>,
157}
158
159pub(crate) struct WithOtherArrayLength<O: Options, L: SizeType> {
160    options: O,
161    _new_array_length: PhantomData<L>,
162}
163
164impl<O: Options, L: SizeLimit> WithOtherLimit<O, L> {
165    #[inline(always)]
166    pub(crate) fn new(options: O, limit: L) -> WithOtherLimit<O, L> {
167        WithOtherLimit {
168            _options: options,
169            new_limit: limit,
170        }
171    }
172}
173
174impl<O: Options, E: ByteOrder> WithOtherEndian<O, E> {
175    #[inline(always)]
176    pub(crate) fn new(options: O) -> WithOtherEndian<O, E> {
177        WithOtherEndian {
178            options,
179            _endian: PhantomData,
180        }
181    }
182}
183
184impl<O: Options, L: SizeType> WithOtherStringLength<O, L> {
185    #[inline(always)]
186    pub(crate) fn new(options: O) -> WithOtherStringLength<O, L> {
187        WithOtherStringLength {
188            options,
189            _new_string_length: PhantomData,
190        }
191    }
192}
193
194impl<O: Options, L: SizeType> WithOtherArrayLength<O, L> {
195    #[inline(always)]
196    pub(crate) fn new(options: O) -> WithOtherArrayLength<O, L> {
197        WithOtherArrayLength {
198            options,
199            _new_array_length: PhantomData,
200        }
201    }
202}
203
204impl<O: Options, E: ByteOrder + 'static> Options for WithOtherEndian<O, E> {
205    type Limit = O::Limit;
206    type Endian = E;
207    type StringSize = O::StringSize;
208    type ArraySize = O::ArraySize;
209
210    #[inline(always)]
211    fn limit(&mut self) -> &mut O::Limit {
212        self.options.limit()
213    }
214}
215
216impl<O: Options, L: SizeLimit + 'static> Options for WithOtherLimit<O, L> {
217    type Limit = L;
218    type Endian = O::Endian;
219    type StringSize = O::StringSize;
220    type ArraySize = O::ArraySize;
221
222    fn limit(&mut self) -> &mut L {
223        &mut self.new_limit
224    }
225}
226
227impl<O: Options, L: SizeType + 'static> Options for WithOtherStringLength<O, L> {
228    type Limit = O::Limit;
229    type Endian = O::Endian;
230    type StringSize = L;
231    type ArraySize = O::ArraySize;
232
233    fn limit(&mut self) -> &mut O::Limit {
234        self.options.limit()
235    }
236}
237
238impl<O: Options, L: SizeType + 'static> Options for WithOtherArrayLength<O, L> {
239    type Limit = O::Limit;
240    type Endian = O::Endian;
241    type StringSize = O::StringSize;
242    type ArraySize = L;
243
244    fn limit(&mut self) -> &mut O::Limit {
245        self.options.limit()
246    }
247}
248
249macro_rules! config_map_limit {
250    ($self:expr, $opts:ident => $call:expr) => {
251        match $self.limit {
252            LimitOption::Unlimited => {
253                let $opts = $opts.with_no_limit();
254                $call
255            }
256            LimitOption::Limited(l) => {
257                let $opts = $opts.with_limit(l);
258                $call
259            }
260        }
261    };
262}
263
264macro_rules! config_map_endian {
265    ($self:expr, $opts:ident => $call:expr) => {
266        match $self.endian {
267            EndianOption::Little => {
268                let $opts = $opts.with_little_endian();
269                $call
270            }
271            EndianOption::Big => {
272                let $opts = $opts.with_big_endian();
273                $call
274            }
275            EndianOption::Native => {
276                let $opts = $opts.with_native_endian();
277                $call
278            }
279        }
280    };
281}
282
283macro_rules! config_map_string_length {
284    ($self:expr, $opts:ident => $call:expr) => {
285        match $self.string_size {
286            LengthOption::U64 => {
287                let $opts = $opts.with_string_size::<U64>();
288                $call
289            }
290            LengthOption::U32 => {
291                let $opts = $opts.with_string_size::<U32>();
292                $call
293            }
294            LengthOption::U16 => {
295                let $opts = $opts.with_string_size::<U16>();
296                $call
297            }
298            LengthOption::U8 => {
299                let $opts = $opts.with_string_size::<U8>();
300                $call
301            }
302        }
303    };
304}
305
306macro_rules! config_map_array_length {
307    ($self:expr, $opts:ident => $call:expr) => {
308        match $self.array_size {
309            LengthOption::U64 => {
310                let $opts = $opts.with_array_size::<U64>();
311                $call
312            }
313            LengthOption::U32 => {
314                let $opts = $opts.with_array_size::<U32>();
315                $call
316            }
317            LengthOption::U16 => {
318                let $opts = $opts.with_array_size::<U16>();
319                $call
320            }
321            LengthOption::U8 => {
322                let $opts = $opts.with_array_size::<U8>();
323                $call
324            }
325        }
326    };
327}
328
329macro_rules! config_map {
330    ($self:expr, $opts:ident => $call:expr) => {{
331        let $opts = DefaultOptions::new();
332        config_map_limit!($self, $opts =>
333            config_map_endian!($self, $opts =>
334                config_map_string_length!($self, $opts =>
335                    config_map_array_length!($self, $opts => $call))))
336    }}
337}
338
339#[allow(clippy::cognitive_complexity)] // https://github.com/rust-lang/rust-clippy/issues/3900
340impl Config {
341    #[inline(always)]
342    pub(crate) fn new() -> Config {
343        Config {
344            limit: LimitOption::Unlimited,
345            endian: EndianOption::Little,
346            string_size: LengthOption::U64,
347            array_size: LengthOption::U64,
348        }
349    }
350
351    /// Sets the byte limit to be unlimited.
352    /// This is the default.
353    #[inline(always)]
354    pub fn no_limit(&mut self) -> &mut Self {
355        self.limit = LimitOption::Unlimited;
356        self
357    }
358
359    /// Sets the byte limit to `limit`.
360    #[inline(always)]
361    pub fn limit(&mut self, limit: u64) -> &mut Self {
362        self.limit = LimitOption::Limited(limit);
363        self
364    }
365
366    /// Sets the endianness to little-endian
367    /// This is the default.
368    #[inline(always)]
369    pub fn little_endian(&mut self) -> &mut Self {
370        self.endian = EndianOption::Little;
371        self
372    }
373
374    /// Sets the endianness to big-endian
375    #[inline(always)]
376    pub fn big_endian(&mut self) -> &mut Self {
377        self.endian = EndianOption::Big;
378        self
379    }
380
381    /// Sets the endianness to the the machine-native endianness
382    #[inline(always)]
383    pub fn native_endian(&mut self) -> &mut Self {
384        self.endian = EndianOption::Native;
385        self
386    }
387
388    /// Sets the size used for lengths of strings
389    #[inline(always)]
390    pub fn string_length(&mut self, size: LengthOption) -> &mut Self {
391        self.string_size = size;
392        self
393    }
394
395    /// Sets the size used for lengths of arrays
396    #[inline(always)]
397    pub fn array_length(&mut self, size: LengthOption) -> &mut Self {
398        self.array_size = size;
399        self
400    }
401
402    /// Serializes a serializable object into a `Vec` of bytes using this configuration
403    #[inline(always)]
404    pub fn serialize<T: ?Sized + serde::Serialize>(&self, t: &T) -> Result<Vec<u8>> {
405        config_map!(self, opts => ::internal::serialize(t, opts))
406    }
407
408    /// Returns the size that an object would be if serialized using Bincode with this configuration
409    #[inline(always)]
410    pub fn serialized_size<T: ?Sized + serde::Serialize>(&self, t: &T) -> Result<u64> {
411        config_map!(self, opts => ::internal::serialized_size(t, opts))
412    }
413
414    /// Serializes an object directly into a `Writer` using this configuration
415    ///
416    /// If the serialization would take more bytes than allowed by the size limit, an error
417    /// is returned and *no bytes* will be written into the `Writer`
418    #[inline(always)]
419    pub fn serialize_into<W: Write, T: ?Sized + serde::Serialize>(
420        &self,
421        w: W,
422        t: &T,
423    ) -> Result<()> {
424        config_map!(self, opts => ::internal::serialize_into(w, t, opts))
425    }
426
427    /// Deserializes a slice of bytes into an instance of `T` using this configuration
428    #[inline(always)]
429    pub fn deserialize<'a, T: serde::Deserialize<'a>>(&self, bytes: &'a [u8]) -> Result<T> {
430        config_map!(self, opts => ::internal::deserialize(bytes, opts))
431    }
432
433    /// TODO: document
434    #[doc(hidden)]
435    #[inline(always)]
436    pub fn deserialize_in_place<'a, R, T>(&self, reader: R, place: &mut T) -> Result<()>
437    where
438        R: BincodeRead<'a>,
439        T: serde::de::Deserialize<'a>,
440    {
441        config_map!(self, opts => ::internal::deserialize_in_place(reader, opts, place))
442    }
443
444    /// Deserializes a slice of bytes with state `seed` using this configuration.
445    #[inline(always)]
446    pub fn deserialize_seed<'a, T: serde::de::DeserializeSeed<'a>>(
447        &self,
448        seed: T,
449        bytes: &'a [u8],
450    ) -> Result<T::Value> {
451        config_map!(self, opts => ::internal::deserialize_seed(seed, bytes, opts))
452    }
453
454    /// Deserializes an object directly from a `Read`er using this configuration
455    ///
456    /// If this returns an `Error`, `reader` may be in an invalid state.
457    #[inline(always)]
458    pub fn deserialize_from<R: Read, T: serde::de::DeserializeOwned>(
459        &self,
460        reader: R,
461    ) -> Result<T> {
462        config_map!(self, opts => ::internal::deserialize_from(reader, opts))
463    }
464
465    /// Deserializes an object directly from a `Read`er with state `seed` using this configuration
466    ///
467    /// If this returns an `Error`, `reader` may be in an invalid state.
468    #[inline(always)]
469    pub fn deserialize_from_seed<'a, R: Read, T: serde::de::DeserializeSeed<'a>>(
470        &self,
471        seed: T,
472        reader: R,
473    ) -> Result<T::Value> {
474        config_map!(self, opts => ::internal::deserialize_from_seed(seed, reader, opts))
475    }
476
477    /// Deserializes an object from a custom `BincodeRead`er using the default configuration.
478    /// It is highly recommended to use `deserialize_from` unless you need to implement
479    /// `BincodeRead` for performance reasons.
480    ///
481    /// If this returns an `Error`, `reader` may be in an invalid state.
482    #[inline(always)]
483    pub fn deserialize_from_custom<'a, R: BincodeRead<'a>, T: serde::de::DeserializeOwned>(
484        &self,
485        reader: R,
486    ) -> Result<T> {
487        config_map!(self, opts => ::internal::deserialize_from_custom(reader, opts))
488    }
489
490    /// Deserializes an object from a custom `BincodeRead`er with state `seed` using the default
491    /// configuration. It is highly recommended to use `deserialize_from` unless you need to
492    /// implement `BincodeRead` for performance reasons.
493    ///
494    /// If this returns an `Error`, `reader` may be in an invalid state.
495    #[inline(always)]
496    pub fn deserialize_from_custom_seed<
497        'a,
498        R: BincodeRead<'a>,
499        T: serde::de::DeserializeSeed<'a>,
500    >(
501        &self,
502        seed: T,
503        reader: R,
504    ) -> Result<T::Value> {
505        config_map!(self, opts => ::internal::deserialize_from_custom_seed(seed, reader, opts))
506    }
507
508    /// Executes the acceptor with a serde::Deserializer instance.
509    /// NOT A PART OF THE STABLE PUBLIC API
510    #[doc(hidden)]
511    pub fn with_deserializer<'a, A, R>(&self, reader: R, acceptor: A) -> A::Output
512    where
513        A: DeserializerAcceptor<'a>,
514        R: BincodeRead<'a>,
515    {
516        config_map!(self, opts => {
517            let mut deserializer = ::de::Deserializer::new(reader, opts);
518            acceptor.accept(&mut deserializer)
519        })
520    }
521
522    /// Executes the acceptor with a serde::Serializer instance.
523    /// NOT A PART OF THE STABLE PUBLIC API
524    #[doc(hidden)]
525    pub fn with_serializer<A, W>(&self, writer: W, acceptor: A) -> A::Output
526    where
527        A: SerializerAcceptor,
528        W: Write,
529    {
530        config_map!(self, opts => {
531            let mut serializer = ::ser::Serializer::new(writer, opts);
532            acceptor.accept(&mut serializer)
533        })
534    }
535}