1 | use std::io::{Read, Write};
|
2 |
|
3 | use self::EndianOption::*;
|
4 | use self::LimitOption::*;
|
5 | use super::{DefaultOptions, Options};
|
6 | use de::read::BincodeRead;
|
7 | use error::Result;
|
8 | use serde;
|
9 |
|
10 | /// A configuration builder whose options Bincode will use
|
11 | /// while serializing and deserializing.
|
12 | ///
|
13 | /// ### Options
|
14 | /// Endianness: The endianness with which multi-byte integers will be read/written. *default: little endian*
|
15 | /// Limit: The maximum number of bytes that will be read/written in a bincode serialize/deserialize. *default: unlimited*
|
16 | ///
|
17 | /// ### Byte Limit Details
|
18 | /// The purpose of byte-limiting is to prevent Denial-Of-Service attacks whereby malicious attackers get bincode
|
19 | /// deserialization to crash your process by allocating too much memory or keeping a connection open for too long.
|
20 | ///
|
21 | /// When a byte limit is set, bincode will return `Err` on any deserialization that goes over the limit, or any
|
22 | /// serialization that goes over the limit.
|
23 | #[derive (Clone, Debug)]
|
24 | #[deprecated (
|
25 | since = "1.3.0" ,
|
26 | note = "please use the `DefaultOptions`/`Options` system instead"
|
27 | )]
|
28 | pub struct Config {
|
29 | limit: LimitOption,
|
30 | endian: EndianOption,
|
31 | }
|
32 |
|
33 | #[derive (Clone, Copy, Debug)]
|
34 | enum LimitOption {
|
35 | Unlimited,
|
36 | Limited(u64),
|
37 | }
|
38 |
|
39 | #[derive (Clone, Copy, Debug)]
|
40 | enum EndianOption {
|
41 | Big,
|
42 | Little,
|
43 | Native,
|
44 | }
|
45 |
|
46 | macro_rules! config_map {
|
47 | ($self:expr, $opts:ident => $call:expr) => {
|
48 | match ($self.limit, $self.endian) {
|
49 | (Unlimited, Little) => {
|
50 | let $opts = DefaultOptions::new()
|
51 | .with_fixint_encoding()
|
52 | .allow_trailing_bytes()
|
53 | .with_no_limit()
|
54 | .with_little_endian();
|
55 | $call
|
56 | }
|
57 | (Unlimited, Big) => {
|
58 | let $opts = DefaultOptions::new()
|
59 | .with_fixint_encoding()
|
60 | .allow_trailing_bytes()
|
61 | .with_no_limit()
|
62 | .with_big_endian();
|
63 | $call
|
64 | }
|
65 | (Unlimited, Native) => {
|
66 | let $opts = DefaultOptions::new()
|
67 | .with_fixint_encoding()
|
68 | .allow_trailing_bytes()
|
69 | .with_no_limit()
|
70 | .with_native_endian();
|
71 | $call
|
72 | }
|
73 |
|
74 | (Limited(l), Little) => {
|
75 | let $opts = DefaultOptions::new()
|
76 | .with_fixint_encoding()
|
77 | .allow_trailing_bytes()
|
78 | .with_limit(l)
|
79 | .with_little_endian();
|
80 | $call
|
81 | }
|
82 | (Limited(l), Big) => {
|
83 | let $opts = DefaultOptions::new()
|
84 | .with_fixint_encoding()
|
85 | .allow_trailing_bytes()
|
86 | .with_limit(l)
|
87 | .with_big_endian();
|
88 | $call
|
89 | }
|
90 | (Limited(l), Native) => {
|
91 | let $opts = DefaultOptions::new()
|
92 | .with_fixint_encoding()
|
93 | .allow_trailing_bytes()
|
94 | .with_limit(l)
|
95 | .with_native_endian();
|
96 | $call
|
97 | }
|
98 | }
|
99 | };
|
100 | }
|
101 |
|
102 | impl Config {
|
103 | #[inline (always)]
|
104 | pub(crate) fn new() -> Config {
|
105 | Config {
|
106 | limit: LimitOption::Unlimited,
|
107 | endian: EndianOption::Little,
|
108 | }
|
109 | }
|
110 |
|
111 | /// Sets the byte limit to be unlimited.
|
112 | /// This is the default.
|
113 | #[inline (always)]
|
114 | pub fn no_limit(&mut self) -> &mut Self {
|
115 | self.limit = LimitOption::Unlimited;
|
116 | self
|
117 | }
|
118 |
|
119 | /// Sets the byte limit to `limit`.
|
120 | #[inline (always)]
|
121 | pub fn limit(&mut self, limit: u64) -> &mut Self {
|
122 | self.limit = LimitOption::Limited(limit);
|
123 | self
|
124 | }
|
125 |
|
126 | /// Sets the endianness to little-endian
|
127 | /// This is the default.
|
128 | #[inline (always)]
|
129 | pub fn little_endian(&mut self) -> &mut Self {
|
130 | self.endian = EndianOption::Little;
|
131 | self
|
132 | }
|
133 |
|
134 | /// Sets the endianness to big-endian
|
135 | #[inline (always)]
|
136 | pub fn big_endian(&mut self) -> &mut Self {
|
137 | self.endian = EndianOption::Big;
|
138 | self
|
139 | }
|
140 |
|
141 | /// Sets the endianness to the the machine-native endianness
|
142 | #[inline (always)]
|
143 | pub fn native_endian(&mut self) -> &mut Self {
|
144 | self.endian = EndianOption::Native;
|
145 | self
|
146 | }
|
147 |
|
148 | /// Serializes a serializable object into a `Vec` of bytes using this configuration
|
149 | #[inline (always)]
|
150 | pub fn serialize<T: ?Sized + serde::Serialize>(&self, t: &T) -> Result<Vec<u8>> {
|
151 | config_map!(self, opts => ::internal::serialize(t, opts))
|
152 | }
|
153 |
|
154 | /// Returns the size that an object would be if serialized using Bincode with this configuration
|
155 | #[inline (always)]
|
156 | pub fn serialized_size<T: ?Sized + serde::Serialize>(&self, t: &T) -> Result<u64> {
|
157 | config_map!(self, opts => ::internal::serialized_size(t, opts))
|
158 | }
|
159 |
|
160 | /// Serializes an object directly into a `Writer` using this configuration
|
161 | ///
|
162 | /// If the serialization would take more bytes than allowed by the size limit, an error
|
163 | /// is returned and *no bytes* will be written into the `Writer`
|
164 | #[inline (always)]
|
165 | pub fn serialize_into<W: Write, T: ?Sized + serde::Serialize>(
|
166 | &self,
|
167 | w: W,
|
168 | t: &T,
|
169 | ) -> Result<()> {
|
170 | config_map!(self, opts => ::internal::serialize_into(w, t, opts))
|
171 | }
|
172 |
|
173 | /// Deserializes a slice of bytes into an instance of `T` using this configuration
|
174 | #[inline (always)]
|
175 | pub fn deserialize<'a, T: serde::Deserialize<'a>>(&self, bytes: &'a [u8]) -> Result<T> {
|
176 | config_map!(self, opts => ::internal::deserialize(bytes, opts))
|
177 | }
|
178 |
|
179 | /// TODO: document
|
180 | #[doc (hidden)]
|
181 | #[inline (always)]
|
182 | pub fn deserialize_in_place<'a, R, T>(&self, reader: R, place: &mut T) -> Result<()>
|
183 | where
|
184 | R: BincodeRead<'a>,
|
185 | T: serde::de::Deserialize<'a>,
|
186 | {
|
187 | config_map!(self, opts => ::internal::deserialize_in_place(reader, opts, place))
|
188 | }
|
189 |
|
190 | /// Deserializes a slice of bytes with state `seed` using this configuration.
|
191 | #[inline (always)]
|
192 | pub fn deserialize_seed<'a, T: serde::de::DeserializeSeed<'a>>(
|
193 | &self,
|
194 | seed: T,
|
195 | bytes: &'a [u8],
|
196 | ) -> Result<T::Value> {
|
197 | config_map!(self, opts => ::internal::deserialize_seed(seed, bytes, opts))
|
198 | }
|
199 |
|
200 | /// Deserializes an object directly from a `Read`er using this configuration
|
201 | ///
|
202 | /// If this returns an `Error`, `reader` may be in an invalid state.
|
203 | #[inline (always)]
|
204 | pub fn deserialize_from<R: Read, T: serde::de::DeserializeOwned>(
|
205 | &self,
|
206 | reader: R,
|
207 | ) -> Result<T> {
|
208 | config_map!(self, opts => ::internal::deserialize_from(reader, opts))
|
209 | }
|
210 |
|
211 | /// Deserializes an object directly from a `Read`er with state `seed` using this configuration
|
212 | ///
|
213 | /// If this returns an `Error`, `reader` may be in an invalid state.
|
214 | #[inline (always)]
|
215 | pub fn deserialize_from_seed<'a, R: Read, T: serde::de::DeserializeSeed<'a>>(
|
216 | &self,
|
217 | seed: T,
|
218 | reader: R,
|
219 | ) -> Result<T::Value> {
|
220 | config_map!(self, opts => ::internal::deserialize_from_seed(seed, reader, opts))
|
221 | }
|
222 |
|
223 | /// Deserializes an object from a custom `BincodeRead`er using the default configuration.
|
224 | /// It is highly recommended to use `deserialize_from` unless you need to implement
|
225 | /// `BincodeRead` for performance reasons.
|
226 | ///
|
227 | /// If this returns an `Error`, `reader` may be in an invalid state.
|
228 | #[inline (always)]
|
229 | pub fn deserialize_from_custom<'a, R: BincodeRead<'a>, T: serde::de::DeserializeOwned>(
|
230 | &self,
|
231 | reader: R,
|
232 | ) -> Result<T> {
|
233 | config_map!(self, opts => ::internal::deserialize_from_custom(reader, opts))
|
234 | }
|
235 |
|
236 | /// Deserializes an object from a custom `BincodeRead`er with state `seed` using the default
|
237 | /// configuration. It is highly recommended to use `deserialize_from` unless you need to
|
238 | /// implement `BincodeRead` for performance reasons.
|
239 | ///
|
240 | /// If this returns an `Error`, `reader` may be in an invalid state.
|
241 | #[inline (always)]
|
242 | pub fn deserialize_from_custom_seed<
|
243 | 'a,
|
244 | R: BincodeRead<'a>,
|
245 | T: serde::de::DeserializeSeed<'a>,
|
246 | >(
|
247 | &self,
|
248 | seed: T,
|
249 | reader: R,
|
250 | ) -> Result<T::Value> {
|
251 | config_map!(self, opts => ::internal::deserialize_from_custom_seed(seed, reader, opts))
|
252 | }
|
253 | }
|
254 | |