| 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 | |