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}