1use crate::source::Stack;
2use crate::{BitWidth, Endianness, NumEncoding, Opaque, StrEncoding, StrLen};
3use core::fmt;
4use core::fmt::Formatter;
5use embedded_io::{Error, ErrorKind, ReadExactError};
6use parse_display::Display;
7
8macro_rules! impl_error {
9 ($name:ident) => {
10 #[cfg(feature = "unstable")]
11 impl core::error::Error for $name {}
12
13 #[cfg(all(not(feature = "unstable"), feature = "std"))]
14 impl std::error::Error for $name {}
15 };
16}
17
18#[derive(Copy, Clone, Eq, PartialEq, Hash, Debug, Display)]
24pub enum Signedness {
25 Signed,
26 Unsigned,
27}
28
29#[derive(Debug, Display)]
31#[non_exhaustive]
32pub enum EncodingError {
33 #[display("IO Error occurred: {:0?}")]
35 IOError(ErrorKind),
36 #[display("Unexpected end of file/buffer")]
38 UnexpectedEnd,
39 #[display("Seek error: {0}")]
41 SeekError(SeekError),
42 #[display("Malformed var-int encoding")]
44 VarIntError,
45 #[display("Invalid bool value")]
47 InvalidBool,
48 #[display("String error: {0}")]
50 StringError(StringError),
51 #[display("A size of {requested} exceeded the max allowed value of {max}")]
53 MaxSizeExceeded { max: usize, requested: usize },
54 #[display("Unrecognized enum variant ({0})")]
56 InvalidVariant(Opaque),
57 #[display(r#"A value of "{value}" is too large to fit in {requested_width}"#)]
59 TooLarge {
60 value: Opaque,
61 requested_width: BitWidth,
62 },
63 #[display("Expected {expected} value, got {got} value instead")]
66 SignMismatch {
67 expected: Signedness,
68 got: Signedness,
69 },
70 #[display("Flatten error: {0}")]
73 FlattenError(FlattenError),
74 #[display("Lock error: couldn't lock a RefCell/Mutex/RwLock or similar")]
76 LockError,
77 #[display("Borrow error: {0}")]
80 BorrowError(BorrowError),
81 #[display("Validation error: {0}")]
83 ValidationError(
84 #[cfg(feature = "alloc")] alloc::string::String,
85 #[cfg(not(feature = "alloc"))] &'static str,
86 ),
87 #[cfg(all(feature = "serde", feature = "alloc"))]
89 #[cfg_attr(feature = "unstable", doc(cfg(feature = "serde")))]
90 #[display("Serde error: {0}")]
91 SerdeError(alloc::string::String),
92 #[cfg(all(feature = "serde", not(feature = "alloc")))]
94 #[cfg_attr(feature = "unstable", doc(cfg(feature = "serde")))]
95 #[display("Serde error")]
96 SerdeError,
97}
98
99#[macro_export]
100macro_rules! val_error {
101 ($($tt:tt)*) => {{
102 $crate::EncodingError::validation_error(::core::format_args!($($tt)*))
103 }};
104}
105
106impl EncodingError {
107 pub fn validation_error<'a>(fmt: fmt::Arguments<'a>) -> Self {
108 #[cfg(feature = "alloc")]
109 #[allow(unused_imports)]
110 {
111 use alloc::string::ToString;
112 Self::ValidationError(fmt.to_string())
113 }
114 #[cfg(not(feature = "alloc"))]
115 {
116 if let Some(str) = fmt.as_str() {
117 Self::ValidationError(str)
118 } else {
119 Self::ValidationError("Unknown")
120 }
121 }
122 }
123
124 pub fn invalid_variant<V>(v: V) -> Self
125 where
126 Opaque: From<V>,
127 {
128 Self::InvalidVariant(Opaque::from(v))
129 }
130}
131
132impl Error for EncodingError {
133 fn kind(&self) -> ErrorKind {
134 match self {
135 EncodingError::IOError(io_error) => io_error.kind().into(),
136 EncodingError::UnexpectedEnd => ErrorKind::Other,
137 EncodingError::FlattenError(_) => ErrorKind::InvalidInput,
138 EncodingError::LockError => ErrorKind::Other,
139 EncodingError::BorrowError(_) => ErrorKind::Other,
140 #[cfg(all(feature = "serde", feature = "alloc"))]
141 EncodingError::SerdeError(_) => ErrorKind::Other,
142 #[cfg(all(feature = "serde", not(feature = "alloc")))]
143 EncodingError::SerdeError => ErrorKind::Other,
144 _ => ErrorKind::InvalidData,
145 }
146 }
147}
148
149impl_error!(EncodingError);
150
151#[cfg(feature = "std")]
152impl From<std::io::Error> for EncodingError {
153 fn from(value: std::io::Error) -> Self {
154 match value.kind() {
155 std::io::ErrorKind::UnexpectedEof => Self::UnexpectedEnd,
156 kind @ _ => Self::IOError(kind.into()),
157 }
158 }
159}
160
161impl From<ErrorKind> for EncodingError {
162 fn from(value: ErrorKind) -> Self {
163 Self::IOError(value)
164 }
165}
166
167impl<T: Error> From<ReadExactError<T>> for EncodingError {
168 fn from(value: ReadExactError<T>) -> Self {
169 match value {
170 ReadExactError::UnexpectedEof => Self::UnexpectedEnd,
171 ReadExactError::Other(io_error) => Self::IOError(io_error.kind().into()),
172 }
173 }
174}
175
176impl From<StringError> for EncodingError {
177 fn from(value: StringError) -> Self {
178 Self::StringError(value)
179 }
180}
181
182impl From<FlattenError> for EncodingError {
183 fn from(value: FlattenError) -> Self {
184 Self::FlattenError(value)
185 }
186}
187
188impl From<BorrowError> for EncodingError {
189 fn from(value: BorrowError) -> Self {
190 Self::BorrowError(value)
191 }
192}
193
194impl From<SeekError> for EncodingError {
195 fn from(value: SeekError) -> Self {
196 Self::SeekError(value)
197 }
198}
199
200#[derive(Debug, Display)]
203#[non_exhaustive]
204pub enum StringError {
205 #[display("String conversion error")]
207 ConversionError,
208 #[display("Invalid characters in string data")]
210 InvalidChar,
211 #[display("String is longer than expected")]
213 TooLong,
214 #[display("Null byte expected")]
217 MissingNull,
218}
219
220impl_error!(StringError);
221
222#[derive(Debug, Display)]
224#[non_exhaustive]
225pub enum FlattenError {
226 #[display("Enum discriminant mismatch: expected {expected}, got {got}")]
227 VariantMismatch { expected: Opaque, got: Opaque },
228 #[display("Boolean mismatch: expected {expected}, got {got}")]
229 BoolMismatch { expected: bool, got: bool },
230 #[display("Length mismatch: expected {expected}, got {got}")]
231 LenMismatch { expected: usize, got: usize },
232}
233
234impl_error!(FlattenError);
235
236#[derive(Debug, Display)]
237#[non_exhaustive]
238pub enum BorrowError {
239 #[display(
240 "String encoding mismatch: expected {found} while decoding a {while_decoding} string"
241 )]
242 StrEncodingMismatch {
243 found: StrEncoding,
244 while_decoding: StrEncoding,
245 },
246 #[display(
247 "String length encoding mismatch: expected {found} while decoding a {while_decoding} string"
248 )]
249 StrLenEncodingMismatch {
250 found: StrLen,
251 while_decoding: StrLen,
252 },
253 #[display("Endianness mismatch: stream contains {found} data, but system uses {system}")]
254 EndiannessMismatch {
255 found: Endianness,
256 system: Endianness,
257 },
258 #[display("Bit width mismatch: stream contains {found} data, but system uses {system}")]
259 BitWidthMismatch { found: BitWidth, system: BitWidth },
260 #[display("Non-borrowable numerical encoding: {num_encoding} can't be directly borrowed")]
261 NonBorrowableNumEncoding { num_encoding: NumEncoding },
262 #[display(
263 "Alignment mismatch: borrowing this data requires its alignment to match the system's"
264 )]
265 AlignmentMismatch,
266}
267
268impl_error!(BorrowError);
269
270#[derive(Debug, Display)]
271#[non_exhaustive]
272pub enum SeekError {
273 #[display("Tried to seek to a negative offset: {0}")]
274 BeforeBeginning(isize),
275 #[display("Tried to seek to an offset beyond the end: {0}")]
276 AfterEnd(usize),
277 #[display("Tried to seek to the beginning/end but they are unknown")]
278 UnknownRange,
279}
280
281impl_error!(SeekError);
282
283#[derive(Debug)]
286pub struct TaggedError {
287 err: EncodingError,
288 stack: Stack,
289}
290
291impl core::fmt::Display for TaggedError {
292 #[inline]
293 fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
294 #[cfg(feature = "alloc")]
295 {
296 if self.stack.frames.is_empty() {
297 return write!(f, "{}", self.err);
298 }
299
300 write!(f, "[{}] {}", self.stack, self.err)?;
301 }
302 #[cfg(not(feature = "alloc"))]
303 {
304 if let crate::source::Frame::Item(x) = self.stack.last_frame {
305 if x == "" {
306 return write!(f, "{}", self.err);
307 }
308 }
309
310 write!(f, "[{}] {}", self.stack, self.err)?;
311 }
312 Ok(())
313 }
314}
315
316impl TaggedError {
317 #[inline]
323 pub const fn from_stack(err: EncodingError, stack: Stack) -> Self {
324 Self { err, stack }
325 }
326}
327
328pub type EncodingResult<T> = Result<T, EncodingError>;