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
286impl core::fmt::Display for DecodeError {
287 fn fmt(
288 &self,
289 f: &mut core::fmt::Formatter<'_>,
290 ) -> core::fmt::Result {
291 // TODO: Improve this?
292 write!(f, "{self:?}")
293 }
294}
295
296impl DecodeError {
297 /// If the current error is `InvalidIntegerType`, change the `expected` and
298 /// `found` values from `Ux` to `Ix`. This is needed to have correct error
299 /// reporting in `src/varint/decode_signed.rs` since this calls
300 /// `src/varint/decode_unsigned.rs` and needs to correct the `expected` and
301 /// `found` types.
302 #[cold]
303 #[inline(never)]
304 pub(crate) fn change_integer_type_to_signed(self) -> Self {
305 match self {
306 | Self::InvalidIntegerType { expected, found } => {
307 Self::InvalidIntegerType {
308 expected: expected.into_signed(),
309 found: found.into_signed(),
310 }
311 },
312 | other => other,
313 }
314 }
315}
316
317/// Indicates which enum variants are allowed
318#[non_exhaustive]
319#[derive(Debug, PartialEq, Eq)]
320pub enum AllowedEnumVariants {
321 /// All values between `min` and `max` (inclusive) are allowed
322 #[allow(missing_docs)]
323 Range { min: u32, max: u32 },
324 /// Each one of these values is allowed
325 Allowed(&'static [u32]),
326}
327
328/// Integer types. Used by [`DecodeError`\]. These types have no purpose other than being shown in errors.
329#[non_exhaustive]
330#[derive(Debug, PartialEq, Eq)]
331#[allow(missing_docs)]
332pub enum IntegerType {
333 U8,
334 U16,
335 U32,
336 U64,
337 U128,
338 Usize,
339
340 I8,
341 I16,
342 I32,
343 I64,
344 I128,
345 Isize,
346
347 Reserved,
348}
349
350impl IntegerType {
351 /// Change the `Ux` value to the associated `Ix` value.
352 /// Returns the old value if `self` is already `Ix`.
353 pub(crate) const fn into_signed(self) -> Self {
354 match self {
355 | Self::U8 => Self::I8,
356 | Self::U16 => Self::I16,
357 | Self::U32 => Self::I32,
358 | Self::U64 => Self::I64,
359 | Self::U128 => Self::I128,
360 | Self::Usize => Self::Isize,
361
362 | other => other,
363 }
364 }
365}