bincode_next/error.rs
1//! Errors that can be encountering by Encoding and Decoding.
2// Necessary to allow dead code since we don't use all variants in all configurations
3#![allow(dead_code)]
4
5#[doc(hidden)]
6#[macro_export]
7macro_rules! bincode_error {
8 (
9 $(#[$meta:meta])*
10 $vis:vis enum $name:ident {
11 $(
12 $(#[$variant_meta:meta])*
13 $variant:ident $( { $( $(#[$field_meta:meta])* $field:ident : $ftype:ty ),* $(,)? } )? $( ( $( $(#[$tuple_meta:meta])* $tname:ident : $ttype:ty ),* $(,)? ) )?
14 ),* $(,)?
15 }
16 ) => {
17 $(#[$meta])*
18 $vis enum $name {
19 $(
20 $(#[$variant_meta])*
21 $variant $( { $( $(#[$field_meta])* $field : $ftype ),* } )? $( ( $( $(#[$tuple_meta])* $ttype ),* ) )?,
22 )*
23 }
24
25 pastey::paste! {
26 $(
27 $(#[$variant_meta])*
28 #[doc(hidden)]
29 #[cold]
30 #[track_caller]
31 #[inline(never)]
32 pub const fn [<cold_ $name:snake _ $variant:snake>]<T>(
33 $($($field : $ftype),*)?
34 $($($tname : $ttype),*)?
35 ) -> core::result::Result<T, $name> {
36 core::result::Result::Err($name::$variant $( { $($field),* } )? $( ( $( $tname ),* ) )?)
37 }
38 )*
39 }
40 };
41}
42
43bincode_error! {
44 /// Errors that can be encountered by encoding a type
45 #[non_exhaustive]
46 #[derive(Debug)]
47 pub enum EncodeError {
48 /// The writer ran out of storage.
49 UnexpectedEnd,
50
51 /// The `RefCell<T>` is already borrowed
52 RefCellAlreadyBorrowed {
53 /// The inner borrow error
54 inner: core::cell::BorrowError,
55 /// the type name of the `RefCell` being encoded that is currently borrowed.
56 type_name: &'static str,
57 },
58
59 /// An uncommon error occurred, see the inner text for more information
60 Other(inner: &'static str),
61
62 /// An uncommon error occurred, see the inner text for more information
63 #[cfg(feature = "alloc")]
64 OtherString(inner: alloc::string::String),
65
66 /// A `std::path::Path` was being encoded but did not contain a valid `&str` representation
67 #[cfg(feature = "std")]
68 InvalidPathCharacters,
69
70 /// The targeted writer encountered an `std::io::Error`
71 #[cfg(feature = "std")]
72 Io {
73 /// The encountered error
74 inner: std::io::Error,
75 /// The amount of bytes that were written before the error occurred
76 index: usize,
77 },
78
79 /// The encoder tried to encode a `Mutex` or `RwLock`, but the locking failed
80 #[cfg(feature = "std")]
81 LockFailed {
82 /// The type name of the mutex for debugging purposes
83 type_name: &'static str,
84 },
85
86 /// The encoder tried to encode a `SystemTime`, but it was before `SystemTime::UNIX_EPOCH`
87 #[cfg(feature = "std")]
88 InvalidSystemTime {
89 /// The error that was thrown by the `SystemTime`
90 inner: std::time::SystemTimeError,
91 /// The `SystemTime` that caused the error
92 time: std::boxed::Box<std::time::SystemTime>,
93 },
94
95 #[cfg(feature = "serde")]
96 /// A serde-specific error that occurred while decoding.
97 Serde(inner: crate::features::serde::EncodeError),
98 }
99}
100
101impl core::fmt::Display for EncodeError {
102 fn fmt(
103 &self,
104 f: &mut core::fmt::Formatter<'_>,
105 ) -> core::fmt::Result {
106 // TODO: Improve this?
107 write!(f, "{self:?}")
108 }
109}
110
111impl core::error::Error for EncodeError {
112 fn source(&self) -> Option<&(dyn core::error::Error + 'static)> {
113 match self {
114 | Self::RefCellAlreadyBorrowed { inner, .. } => Some(inner),
115 #[cfg(feature = "std")]
116 | Self::Io { inner, .. } => Some(inner),
117 #[cfg(feature = "std")]
118 | Self::InvalidSystemTime { inner, .. } => Some(inner),
119 | _ => None,
120 }
121 }
122}
123impl core::error::Error for DecodeError {
124 fn source(&self) -> Option<&(dyn core::error::Error + 'static)> {
125 match self {
126 | Self::Utf8 { inner } => Some(inner),
127 | _ => None,
128 }
129 }
130}
131
132bincode_error! {
133 /// Errors that can be encountered by decoding a type
134 #[non_exhaustive]
135 #[derive(Debug)]
136 pub enum DecodeError {
137 /// The reader reached its end but more bytes were expected.
138 UnexpectedEnd {
139 /// Gives an estimate of how many extra bytes are needed.
140 ///
141 /// **Note**: this is only an estimate and not indicative of the actual bytes needed.
142 ///
143 /// **Note**: Bincode has no look-ahead mechanism. This means that this will only return the amount of bytes to be read for the current action, and not take into account the entire data structure being read.
144 additional: usize,
145 },
146
147 /// The given configuration limit was exceeded
148 LimitExceeded,
149
150 /// Invalid type was found. The decoder tried to read type `expected`, but found type `found` instead.
151 InvalidIntegerType {
152 /// The type that was being read from the reader
153 expected: IntegerType,
154 /// The type that was encoded in the data
155 found: IntegerType,
156 },
157
158 /// The decoder tried to decode any of the `NonZero*` types but the value is zero
159 NonZeroTypeIsZero {
160 /// The type that was being read from the reader
161 non_zero_type: IntegerType,
162 },
163
164 /// Invalid enum variant was found. The decoder tried to decode variant index `found`, but the variant index should be between `min` and `max`.
165 UnexpectedVariant {
166 /// The type name that was being decoded.
167 type_name: &'static str,
168
169 /// The variants that are allowed
170 allowed: &'static AllowedEnumVariants,
171
172 /// The index of the enum that the decoder encountered
173 found: u32,
174 },
175
176 /// The decoder tried to decode a `str`, but an utf8 error was encountered.
177 Utf8 {
178 /// The inner error
179 inner: core::str::Utf8Error,
180 },
181
182 /// The decoder tried to decode a `char` and failed. The given buffer contains the bytes that are read at the moment of failure.
183 InvalidCharEncoding(inner: [u8; 4]),
184
185 /// The decoder tried to decode a `bool` and failed. The given value is what is actually read.
186 InvalidBooleanValue(inner: u8),
187
188 /// Invalid CBOR "additional info" value (28-31) was found.
189 InvalidCborInfo(inner: u8),
190
191 /// The decoder tried to decode an array of length `required`, but the binary data contained an array of length `found`.
192 ArrayLengthMismatch {
193 /// The length of the array required by the rust type.
194 required: usize,
195 /// The length of the array found in the binary format.
196 found: usize,
197 },
198
199 /// The encoded value is outside of the range of the target usize type.
200 ///
201 /// This can happen if an usize was encoded on an architecture with a larger
202 /// usize type and then decoded on an architecture with a smaller one. For
203 /// example going from a 64 bit architecture to a 32 or 16 bit one may
204 /// cause this error.
205 OutsideUsizeRange(inner: u64),
206
207 /// The encoded value is outside of the range of the target isize type.
208 ///
209 /// This can happen if an isize was encoded on an architecture with a larger
210 /// isize type and then decoded on an architecture with a smaller one. For
211 /// example going from a 64 bit architecture to a 32 or 16 bit one may
212 /// cause this error.
213 OutsideIsizeRange(inner: i64),
214
215 /// Tried to decode an enum with no variants
216 EmptyEnum {
217 /// The type that was being decoded
218 type_name: &'static str,
219 },
220
221 /// The decoder tried to decode a Duration and overflowed the number of seconds.
222 InvalidDuration {
223 /// The number of seconds in the duration.
224 secs: u64,
225
226 /// The number of nanoseconds in the duration, which when converted to seconds and added to
227 /// `secs`, overflows a `u64`.
228 nanos: u32,
229 },
230
231 /// The decoder tried to decode a `SystemTime` and overflowed
232 InvalidSystemTime {
233 /// The duration which could not have been added to
234 /// [`UNIX_EPOCH`\](`std::time::SystemTime::UNIX_EPOCH`)
235 duration: core::time::Duration,
236 },
237
238 /// The decoder tried to decode a `CString`, but the incoming data contained a 0 byte
239 #[cfg(feature = "std")]
240 CStringNulError {
241 /// Nul byte position
242 position: usize,
243 },
244
245 /// The reader encountered an IO error but more bytes were expected.
246 #[cfg(feature = "std")]
247 Io {
248 /// The IO error expected
249 inner: std::io::Error,
250
251 /// Gives an estimate of how many extra bytes are needed.
252 ///
253 /// **Note**: this is only an estimate and not indicative of the actual bytes needed.
254 ///
255 /// **Note**: Bincode has no look-ahead mechanism. This means that this will only return the amount of bytes to be read for the current action, and not take into account the entire data structure being read.
256 additional: usize,
257 },
258
259 /// An uncommon error occurred, see the inner text for more information
260 Other(inner: &'static str),
261
262 /// An uncommon error occurred, see the inner text for more information
263 #[cfg(feature = "alloc")]
264 OtherString(inner: alloc::string::String),
265
266 #[cfg(feature = "serde")]
267 /// A serde-specific error that occurred while decoding.
268 Serde(inner: crate::features::serde::DecodeError),
269
270 /// The schema of the type being decoded does not match the schema of the encoded data.
271 SchemaMismatch {
272 /// The hash that was expected by the decoder
273 expected: u64,
274 /// The hash that was found in the encoded data
275 actual: u64,
276 },
277
278 /// The decoder tried to decode a map, but a duplicate key was found.
279 DuplicateMapKey,
280
281 /// The decoder tried to decode a map, but the keys were not in the correct order.
282 InvalidMapOrder,
283 }
284}
285
286#[cfg(feature = "serde")]
287impl From<crate::features::serde::DecodeError> for crate::error::DecodeError {
288 fn from(err: crate::features::serde::DecodeError) -> Self {
289 Self::Serde(err)
290 }
291}
292
293#[cfg(feature = "serde")]
294#[doc(hidden)]
295#[must_use]
296/// Helper function to convert an error into a `DecodeError`.
297pub const fn decode_err_from(e: crate::features::serde::DecodeError) -> DecodeError {
298 DecodeError::Serde(e)
299}
300
301impl core::fmt::Display for DecodeError {
302 fn fmt(
303 &self,
304 f: &mut core::fmt::Formatter<'_>,
305 ) -> core::fmt::Result {
306 // TODO: Improve this?
307 write!(f, "{self:?}")
308 }
309}
310
311impl DecodeError {
312 /// If the current error is `InvalidIntegerType`, change the `expected` and
313 /// `found` values from `Ux` to `Ix`. This is needed to have correct error
314 /// reporting in `src/varint/decode_signed.rs` since this calls
315 /// `src/varint/decode_unsigned.rs` and needs to correct the `expected` and
316 /// `found` types.
317 #[cold]
318 #[inline(never)]
319 pub(crate) fn change_integer_type_to_signed(self) -> Self {
320 match self {
321 | Self::InvalidIntegerType { expected, found } => {
322 Self::InvalidIntegerType {
323 expected: expected.into_signed(),
324 found: found.into_signed(),
325 }
326 },
327 | other => other,
328 }
329 }
330}
331
332/// Indicates which enum variants are allowed
333#[non_exhaustive]
334#[derive(Debug, PartialEq, Eq)]
335pub enum AllowedEnumVariants {
336 /// All values between `min` and `max` (inclusive) are allowed
337 #[allow(missing_docs)]
338 Range { min: u32, max: u32 },
339 /// Each one of these values is allowed
340 Allowed(&'static [u32]),
341}
342
343/// Integer types. Used by [`DecodeError`\]. These types have no purpose other than being shown in errors.
344#[non_exhaustive]
345#[derive(Debug, PartialEq, Eq)]
346#[allow(missing_docs)]
347pub enum IntegerType {
348 U8,
349 U16,
350 U32,
351 U64,
352 U128,
353 Usize,
354
355 I8,
356 I16,
357 I32,
358 I64,
359 I128,
360 Isize,
361
362 Reserved,
363}
364
365impl IntegerType {
366 /// Change the `Ux` value to the associated `Ix` value.
367 /// Returns the old value if `self` is already `Ix`.
368 pub(crate) const fn into_signed(self) -> Self {
369 match self {
370 | Self::U8 => Self::I8,
371 | Self::U16 => Self::I16,
372 | Self::U32 => Self::I32,
373 | Self::U64 => Self::I64,
374 | Self::U128 => Self::I128,
375 | Self::Usize => Self::Isize,
376
377 | other => other,
378 }
379 }
380}