bincode/
error.rs

1//! Errors that can be encountering by Encoding and Decoding.
2
3/// Errors that can be encountered by encoding a type
4#[non_exhaustive]
5#[derive(Debug)]
6pub enum EncodeError {
7    /// The writer ran out of storage.
8    UnexpectedEnd,
9
10    /// The `RefCell<T>` is already borrowed
11    RefCellAlreadyBorrowed {
12        /// The inner borrow error
13        inner: core::cell::BorrowError,
14        /// the type name of the RefCell being encoded that is currently borrowed.
15        type_name: &'static str,
16    },
17
18    /// An uncommon error occurred, see the inner text for more information
19    Other(&'static str),
20
21    /// An uncommon error occurred, see the inner text for more information
22    #[cfg(feature = "alloc")]
23    OtherString(alloc::string::String),
24
25    /// A `std::path::Path` was being encoded but did not contain a valid `&str` representation
26    #[cfg(feature = "std")]
27    InvalidPathCharacters,
28
29    /// The targeted writer encountered an `std::io::Error`
30    #[cfg(feature = "std")]
31    Io {
32        /// The encountered error
33        inner: std::io::Error,
34        /// The amount of bytes that were written before the error occurred
35        index: usize,
36    },
37
38    /// The encoder tried to encode a `Mutex` or `RwLock`, but the locking failed
39    #[cfg(feature = "std")]
40    LockFailed {
41        /// The type name of the mutex for debugging purposes
42        type_name: &'static str,
43    },
44
45    /// The encoder tried to encode a `SystemTime`, but it was before `SystemTime::UNIX_EPOCH`
46    #[cfg(feature = "std")]
47    InvalidSystemTime {
48        /// The error that was thrown by the SystemTime
49        inner: std::time::SystemTimeError,
50        /// The SystemTime that caused the error
51        time: std::boxed::Box<std::time::SystemTime>,
52    },
53
54    #[cfg(feature = "serde")]
55    /// A serde-specific error that occurred while decoding.
56    Serde(crate::features::serde::EncodeError),
57}
58
59impl core::fmt::Display for EncodeError {
60    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
61        // TODO: Improve this?
62        write!(f, "{:?}", self)
63    }
64}
65
66impl core::error::Error for EncodeError {
67    fn source(&self) -> Option<&(dyn core::error::Error + 'static)> {
68        match self {
69            Self::RefCellAlreadyBorrowed { inner, .. } => Some(inner),
70            #[cfg(feature = "std")]
71            Self::Io { inner, .. } => Some(inner),
72            #[cfg(feature = "std")]
73            Self::InvalidSystemTime { inner, .. } => Some(inner),
74            _ => None,
75        }
76    }
77}
78impl core::error::Error for DecodeError {
79    fn source(&self) -> Option<&(dyn core::error::Error + 'static)> {
80        match self {
81            Self::Utf8 { inner } => Some(inner),
82            _ => None,
83        }
84    }
85}
86
87/// Errors that can be encountered by decoding a type
88#[non_exhaustive]
89#[derive(Debug)]
90pub enum DecodeError {
91    /// The reader reached its end but more bytes were expected.
92    UnexpectedEnd {
93        /// Gives an estimate of how many extra bytes are needed.
94        ///
95        /// **Note**: this is only an estimate and not indicative of the actual bytes needed.
96        ///
97        /// **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.
98        additional: usize,
99    },
100
101    /// The given configuration limit was exceeded
102    LimitExceeded,
103
104    /// Invalid type was found. The decoder tried to read type `expected`, but found type `found` instead.
105    InvalidIntegerType {
106        /// The type that was being read from the reader
107        expected: IntegerType,
108        /// The type that was encoded in the data
109        found: IntegerType,
110    },
111
112    /// The decoder tried to decode any of the `NonZero*` types but the value is zero
113    NonZeroTypeIsZero {
114        /// The type that was being read from the reader
115        non_zero_type: IntegerType,
116    },
117
118    /// Invalid enum variant was found. The decoder tried to decode variant index `found`, but the variant index should be between `min` and `max`.
119    UnexpectedVariant {
120        /// The type name that was being decoded.
121        type_name: &'static str,
122
123        /// The variants that are allowed
124        allowed: &'static AllowedEnumVariants,
125
126        /// The index of the enum that the decoder encountered
127        found: u32,
128    },
129
130    /// The decoder tried to decode a `str`, but an utf8 error was encountered.
131    Utf8 {
132        /// The inner error
133        inner: core::str::Utf8Error,
134    },
135
136    /// The decoder tried to decode a `char` and failed. The given buffer contains the bytes that are read at the moment of failure.
137    InvalidCharEncoding([u8; 4]),
138
139    /// The decoder tried to decode a `bool` and failed. The given value is what is actually read.
140    InvalidBooleanValue(u8),
141
142    /// The decoder tried to decode an array of length `required`, but the binary data contained an array of length `found`.
143    ArrayLengthMismatch {
144        /// The length of the array required by the rust type.
145        required: usize,
146        /// The length of the array found in the binary format.
147        found: usize,
148    },
149
150    /// The encoded value is outside of the range of the target usize type.
151    ///
152    /// This can happen if an usize was encoded on an architecture with a larger
153    /// usize type and then decoded on an architecture with a smaller one. For
154    /// example going from a 64 bit architecture to a 32 or 16 bit one may
155    /// cause this error.
156    OutsideUsizeRange(u64),
157
158    /// Tried to decode an enum with no variants
159    EmptyEnum {
160        /// The type that was being decoded
161        type_name: &'static str,
162    },
163
164    /// The decoder tried to decode a Duration and overflowed the number of seconds.
165    InvalidDuration {
166        /// The number of seconds in the duration.
167        secs: u64,
168
169        /// The number of nanoseconds in the duration, which when converted to seconds and added to
170        /// `secs`, overflows a `u64`.
171        nanos: u32,
172    },
173
174    /// The decoder tried to decode a SystemTime and overflowed
175    InvalidSystemTime {
176        /// The duration which could not have been added to
177        /// [`UNIX_EPOCH`](std::time::SystemTime::UNIX_EPOCH)
178        duration: core::time::Duration,
179    },
180
181    /// The decoder tried to decode a `CString`, but the incoming data contained a 0 byte
182    #[cfg(feature = "std")]
183    CStringNulError {
184        /// Nul byte position
185        position: usize,
186    },
187
188    /// The reader encountered an IO error but more bytes were expected.
189    #[cfg(feature = "std")]
190    Io {
191        /// The IO error expected
192        inner: std::io::Error,
193
194        /// Gives an estimate of how many extra bytes are needed.
195        ///
196        /// **Note**: this is only an estimate and not indicative of the actual bytes needed.
197        ///
198        /// **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.
199        additional: usize,
200    },
201
202    /// An uncommon error occurred, see the inner text for more information
203    Other(&'static str),
204
205    /// An uncommon error occurred, see the inner text for more information
206    #[cfg(feature = "alloc")]
207    OtherString(alloc::string::String),
208
209    #[cfg(feature = "serde")]
210    /// A serde-specific error that occurred while decoding.
211    Serde(crate::features::serde::DecodeError),
212}
213
214impl core::fmt::Display for DecodeError {
215    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
216        // TODO: Improve this?
217        write!(f, "{:?}", self)
218    }
219}
220
221impl DecodeError {
222    /// If the current error is `InvalidIntegerType`, change the `expected` and
223    /// `found` values from `Ux` to `Ix`. This is needed to have correct error
224    /// reporting in src/varint/decode_signed.rs since this calls
225    /// src/varint/decode_unsigned.rs and needs to correct the `expected` and
226    /// `found` types.
227    pub(crate) fn change_integer_type_to_signed(self) -> DecodeError {
228        match self {
229            Self::InvalidIntegerType { expected, found } => Self::InvalidIntegerType {
230                expected: expected.into_signed(),
231                found: found.into_signed(),
232            },
233            other => other,
234        }
235    }
236}
237
238/// Indicates which enum variants are allowed
239#[non_exhaustive]
240#[derive(Debug, PartialEq, Eq)]
241pub enum AllowedEnumVariants {
242    /// All values between `min` and `max` (inclusive) are allowed
243    #[allow(missing_docs)]
244    Range { min: u32, max: u32 },
245    /// Each one of these values is allowed
246    Allowed(&'static [u32]),
247}
248
249/// Integer types. Used by [DecodeError]. These types have no purpose other than being shown in errors.
250#[non_exhaustive]
251#[derive(Debug, PartialEq, Eq)]
252#[allow(missing_docs)]
253pub enum IntegerType {
254    U8,
255    U16,
256    U32,
257    U64,
258    U128,
259    Usize,
260
261    I8,
262    I16,
263    I32,
264    I64,
265    I128,
266    Isize,
267
268    Reserved,
269}
270
271impl IntegerType {
272    /// Change the `Ux` value to the associated `Ix` value.
273    /// Returns the old value if `self` is already `Ix`.
274    pub(crate) const fn into_signed(self) -> Self {
275        match self {
276            Self::U8 => Self::I8,
277            Self::U16 => Self::I16,
278            Self::U32 => Self::I32,
279            Self::U64 => Self::I64,
280            Self::U128 => Self::I128,
281            Self::Usize => Self::Isize,
282
283            other => other,
284        }
285    }
286}