bincode_next/de/mod.rs
1//! Decoder-based structs and traits.
2
3mod decoder;
4mod impl_core;
5mod impl_tuples;
6mod impls;
7
8use self::{
9 decoder::WithContext,
10 read::{BorrowReader, Reader},
11};
12use crate::{
13 config::{Config, InternalLimitConfig},
14 error::DecodeError,
15 utils::Sealed,
16};
17
18pub mod read;
19
20pub use self::decoder::DecoderImpl;
21
22/// Trait that makes a type able to be decoded, akin to serde's `DeserializeOwned` trait.
23///
24/// Some types may require specific contexts. For example, to decode arena-based collections, an arena allocator must be provided as a context. In these cases, the context type `Context` should be specified or bounded.
25///
26/// This trait should be implemented for types which do not have references to data in the reader. For types that contain e.g. `&str` and `&[u8]`, implement [`BorrowDecode`\] instead.
27///
28/// Whenever you derive `Decode` for your type, the base trait `BorrowDecode` is automatically implemented.
29///
30/// This trait will be automatically implemented with unbounded `Context` if you enable the `derive` feature and add `#[derive(bincode::Decode)]` to your type. Note that if the type contains any lifetimes, `BorrowDecode` will be implemented instead.
31///
32/// # Implementing this trait manually
33///
34/// If you want to implement this trait for your type, the easiest way is to add a `#[derive(bincode::Decode)]`, build and check your `target/generated/bincode/` folder. This should generate a `<Struct name>_Decode.rs` file.
35///
36/// For this struct:
37///
38/// ```
39/// struct Entity {
40/// pub x: f32,
41/// pub y: f32,
42/// }
43/// ```
44///
45/// It will look something like:
46///
47/// ```
48/// # struct Entity {
49/// # pub x: f32,
50/// # pub y: f32,
51/// # }
52/// impl<Context> bincode_next::Decode<Context> for Entity {
53/// fn decode<D: bincode_next::de::Decoder<Context = Context>>(
54/// decoder: &mut D,
55/// ) -> core::result::Result<Self, bincode_next::error::DecodeError> {
56/// Ok(Self {
57/// x: bincode_next::Decode::decode(decoder)?,
58/// y: bincode_next::Decode::decode(decoder)?,
59/// })
60/// }
61/// }
62/// impl<'de, Context> bincode_next::BorrowDecode<'de, Context> for Entity {
63/// fn borrow_decode<D: bincode_next::de::BorrowDecoder<'de, Context = Context>>(
64/// decoder: &mut D,
65/// ) -> core::result::Result<Self, bincode_next::error::DecodeError> {
66/// Ok(Self {
67/// x: bincode_next::BorrowDecode::borrow_decode(decoder)?,
68/// y: bincode_next::BorrowDecode::borrow_decode(decoder)?,
69/// })
70/// }
71/// }
72/// ```
73///
74/// From here you can add/remove fields, or add custom logic.
75///
76/// To get specific integer types, you can use:
77/// ```
78/// # struct Foo;
79/// # impl<Context> bincode_next::Decode<Context> for Foo {
80/// # fn decode<D: bincode_next::de::Decoder<Context = Context>>(
81/// # decoder: &mut D,
82/// # ) -> core::result::Result<Self, bincode_next::error::DecodeError> {
83/// let x: u8 = bincode_next::Decode::<Context>::decode(decoder)?;
84/// let x = <u8 as bincode_next::Decode::<Context>>::decode(decoder)?;
85/// # Ok(Foo)
86/// # }
87/// # }
88/// # bincode_next::impl_borrow_decode!(Foo);
89/// ```
90///
91/// You can use `Context` to require contexts for decoding a type:
92/// ```
93/// # /// # use bumpalo::Bump;
94/// use bincode_next::de::Decoder;
95/// use bincode_next::error::DecodeError;
96/// struct BytesInArena<'a>(bumpalo::collections::Vec<'a, u8>);
97/// impl<'a> bincode_next::Decode<&'a bumpalo::Bump> for BytesInArena<'a> {
98/// fn decode<D: Decoder>(decoder: &mut D) -> Result<Self, DecodeError> {
99/// todo!()
100/// }
101/// # }
102/// ```
103pub trait Decode<Context>: Sized {
104 /// Attempt to decode this type with the given [`Decode`\].
105 ///
106 /// # Errors
107 ///
108 /// Returns any error encountered during decoding.
109 fn decode<D: Decoder<Context = Context>>(decoder: &mut D) -> Result<Self, DecodeError>;
110}
111
112/// Trait that makes a type able to be decoded, akin to serde's `Deserialize` trait.
113///
114/// This trait should be implemented for types that contain borrowed data, like `&str` and `&[u8]`. If your type does not have borrowed data, consider implementing [`Decode`\] instead.
115///
116/// This trait will be automatically implemented if you enable the `derive` feature and add `#[derive(bincode::Decode)]` to a type with a lifetime.
117pub trait BorrowDecode<'de, Context>: Sized {
118 /// Attempt to decode this type with the given [`BorrowDecode`\].
119 ///
120 /// # Errors
121 ///
122 /// Returns any error encountered during decoding.
123 fn borrow_decode<D: BorrowDecoder<'de, Context = Context>>(
124 decoder: &mut D,
125 ) -> Result<Self, DecodeError>;
126}
127
128/// Helper macro to implement `BorrowDecode` for any type that implements `Decode`.
129#[macro_export]
130macro_rules! impl_borrow_decode {
131 ($ty:ty $(, $param:tt)*) => {
132 impl<'de $(, $param)*, __Context> $crate::BorrowDecode<'de, __Context> for $ty {
133 fn borrow_decode<D: $crate::de::BorrowDecoder<'de, Context = __Context>>(
134 decoder: &mut D,
135 ) -> core::result::Result<Self, $crate::error::DecodeError> {
136 $crate::Decode::decode(decoder)
137 }
138 }
139 };
140}
141
142/// Helper macro to implement `BorrowDecode` for any type that implements `Decode`.
143#[macro_export]
144macro_rules! impl_borrow_decode_with_context {
145 ($ty:ty, $context:ty $(, $param:tt)*) => {
146 impl<'de $(, $param)*> $crate::BorrowDecode<'de, $context> for $ty {
147 fn borrow_decode<D: $crate::de::BorrowDecoder<'de, Context = $context>>(
148 decoder: &mut D,
149 ) -> core::result::Result<Self, $crate::error::DecodeError> {
150 $crate::Decode::decode(decoder)
151 }
152 }
153 };
154}
155
156/// Any source that can decode basic types. This type is most notably implemented for [Decoder].
157pub trait Decoder: Sealed {
158 /// The concrete [Reader] type
159 type R: Reader;
160
161 /// The concrete [Config] type
162 type C: Config;
163
164 /// The decoding context type
165 type Context;
166
167 /// Returns the decoding context
168 fn context(&mut self) -> &mut Self::Context;
169
170 /// Wraps decoder with a context
171 fn with_context<C>(&mut self, context: C) -> WithContext<'_, Self, C> {
172 WithContext {
173 decoder: self,
174 context,
175 }
176 }
177
178 /// Returns a mutable reference to the reader
179 fn reader(&mut self) -> &mut Self::R;
180
181 /// Returns a reference to the config
182 fn config(&self) -> &Self::C;
183
184 /// Claim that `n` bytes are going to be read from the decoder.
185 /// This can be used to validate `Configuration::Limit<N>()`.
186 ///
187 /// # Errors
188 ///
189 /// Returns `DecodeError::LimitExceeded` if the limit is exceeded.
190 fn claim_bytes_read(&mut self, n: usize) -> Result<(), DecodeError>;
191
192 /// Claim that we're going to read a container which contains `len` entries of `T`.
193 /// This will correctly handle overflowing if `len * size_of::<T>() > usize::max_value`
194 ///
195 /// # Errors
196 ///
197 /// Returns `DecodeError::LimitExceeded` if the limit is exceeded or if `len * size_of::<T>()` overflows.
198 fn claim_container_read<T>(&mut self, len: usize) -> Result<(), DecodeError> {
199 if <Self::C as InternalLimitConfig>::LIMIT.is_some() {
200 len.checked_mul(core::mem::size_of::<T>())
201 .map_or(Err(DecodeError::LimitExceeded), |val| {
202 self.claim_bytes_read(val)
203 })
204 } else {
205 Ok(())
206 }
207 }
208
209 /// Notify the decoder that `n` bytes are being reclaimed.
210 ///
211 /// When decoding container types, a typical implementation would claim to read `len * size_of::<T>()` bytes.
212 /// This is to ensure that bincode won't allocate several GB of memory while constructing the container.
213 ///
214 /// Because the implementation claims `len * size_of::<T>()`, but then has to decode each `T`, this would be marked
215 /// as double. This function allows us to un-claim each `T` that gets decoded.
216 ///
217 /// We cannot check if `len * size_of::<T>()` is valid without claiming it, because this would mean that if you have
218 /// a nested container (e.g. `Vec<Vec<T>>`), it does not know how much memory is already claimed, and could easily
219 /// allocate much more than the user intends.
220 /// ```
221 /// # use bincode_next::de::{Decode, Decoder};
222 /// # use bincode_next::error::DecodeError;
223 /// # struct Container<T>(Vec<T>);
224 /// # impl<T> Container<T> {
225 /// # fn with_capacity(cap: usize) -> Self {
226 /// # Self(Vec::with_capacity(cap))
227 /// # }
228 /// #
229 /// # fn push(&mut self, t: T) {
230 /// # self.0.push(t);
231 /// # }
232 /// # }
233 /// impl<Context, T: Decode<Context>> Decode<Context> for Container<T> {
234 /// fn decode<D: Decoder<Context = Context>>(decoder: &mut D) -> Result<Self, DecodeError> {
235 /// let len = u64::decode(decoder)?;
236 /// let len: usize = len.try_into().map_err(|_| DecodeError::OutsideUsizeRange(len))?;
237 /// // Make sure we don't allocate too much memory
238 /// decoder.claim_bytes_read(len * core::mem::size_of::<T>());
239 ///
240 /// let mut result = Container::with_capacity(len);
241 /// for _ in 0..len {
242 /// // un-claim the memory
243 /// decoder.unclaim_bytes_read(core::mem::size_of::<T>());
244 /// result.push(T::decode(decoder)?)
245 /// }
246 /// Ok(result)
247 /// }
248 /// }
249 /// impl<'de, Context, T: bincode_next::BorrowDecode<'de, Context>> bincode_next::BorrowDecode<'de, Context> for Container<T> {
250 /// fn borrow_decode<D: bincode_next::de::BorrowDecoder<'de, Context = Context>>(
251 /// decoder: &mut D,
252 /// ) -> core::result::Result<Self, bincode_next::error::DecodeError> {
253 /// let len = u64::borrow_decode(decoder)?;
254 /// let len: usize = len.try_into().map_err(|_| DecodeError::OutsideUsizeRange(len))?;
255 /// // Make sure we don't allocate too much memory
256 /// decoder.claim_bytes_read(len * core::mem::size_of::<T>());
257 ///
258 /// let mut result = Container::with_capacity(len);
259 /// for _ in 0..len {
260 /// // un-claim the memory
261 /// decoder.unclaim_bytes_read(core::mem::size_of::<T>());
262 /// result.push(T::borrow_decode(decoder)?)
263 /// }
264 /// Ok(result)
265 /// }
266 /// }
267 /// ```
268 fn unclaim_bytes_read(&mut self, n: usize);
269}
270
271/// Any source that can decode basic types. This type is most notably implemented for [Decoder].
272///
273/// This is an extension of [Decode] that can also return borrowed data.
274pub trait BorrowDecoder<'de>: Decoder {
275 /// The concrete [`BorrowReader`\] type
276 type BR: BorrowReader<'de>;
277
278 /// Returns a mutable reference to the borrow reader
279 fn borrow_reader(&mut self) -> &mut Self::BR;
280}
281
282impl<T> Decoder for &mut T
283where
284 T: Decoder,
285{
286 type R = T::R;
287
288 type C = T::C;
289
290 type Context = T::Context;
291
292 fn reader(&mut self) -> &mut Self::R {
293 T::reader(self)
294 }
295
296 fn config(&self) -> &Self::C {
297 T::config(self)
298 }
299
300 #[inline]
301 fn claim_bytes_read(&mut self, n: usize) -> Result<(), DecodeError> {
302 T::claim_bytes_read(self, n)
303 }
304
305 #[inline]
306 fn unclaim_bytes_read(&mut self, n: usize) {
307 T::unclaim_bytes_read(self, n);
308 }
309
310 fn context(&mut self) -> &mut Self::Context {
311 T::context(self)
312 }
313}
314
315impl<'de, T> BorrowDecoder<'de> for &mut T
316where
317 T: BorrowDecoder<'de>,
318{
319 type BR = T::BR;
320
321 fn borrow_reader(&mut self) -> &mut Self::BR {
322 T::borrow_reader(self)
323 }
324}
325
326/// Decodes only the option variant from the decoder. Will not read any more data than that.
327#[inline]
328pub(crate) fn decode_option_variant<D: Decoder>(
329 decoder: &mut D,
330 type_name: &'static str,
331) -> Result<Option<()>, DecodeError> {
332 let is_some = u8::decode(decoder)?;
333 match is_some {
334 0 => Ok(None),
335 1 => Ok(Some(())),
336 x => Err(DecodeError::UnexpectedVariant {
337 found: u32::from(x),
338 allowed: &crate::error::AllowedEnumVariants::Range { max: 1, min: 0 },
339 type_name,
340 }),
341 }
342}
343
344/// Decodes the length of any slice, container, etc from the decoder
345#[inline]
346pub(crate) fn decode_slice_len<D: Decoder>(decoder: &mut D) -> Result<usize, DecodeError> {
347 let v = u64::decode(decoder)?;
348
349 v.try_into().map_err(|_| DecodeError::OutsideUsizeRange(v))
350}