1use core::convert::Infallible;
10use core::fmt;
11#[cfg(feature = "std")]
12use std::error::Error as StdError;
13#[cfg(all(not(feature = "std"), feature = "newer-rust-version"))]
14if_rust_version::if_rust_version! {
15 >= 1.81 {
16 use core::error::Error as StdError;
17 }
18}
19
20#[cfg(feature = "std")]
21macro_rules! if_std_error {
22 ({ $($if_yes:tt)* } $(else { $($if_not:tt)* })?) => {
23 #[cfg_attr(docsrs, doc(cfg(any(feature = "std", all(feature = "newer-rust-version", rust_version = ">= 1.81.0")))))]
24 $($if_yes)*
25 }
26}
27
28#[cfg(all(not(feature = "std"), feature = "newer-rust-version"))]
29macro_rules! if_std_error {
30 ({ $($if_yes:tt)* } $(else { $($if_not:tt)* })?) => {
31 if_rust_version::if_rust_version! {
32 >= 1.81 {
33 #[cfg_attr(docsrs, doc(cfg(any(feature = "std", all(feature = "newer-rust-version", rust_version = ">= 1.81.0")))))]
34 $($if_yes)*
35 } $(else { $($if_not)* })?
36 }
37 }
38}
39
40#[cfg(all(not(feature = "std"), not(feature = "newer-rust-version")))]
41macro_rules! if_std_error {
42 ({ $($if_yes:tt)* } $(else { $($if_not:tt)* })?) => {
43 $($($if_not)*)?
44 }
45}
46
47macro_rules! write_err {
53 ($writer:expr, $string:literal $(, $args:expr)*; $source:expr) => {
54 {
55 if_std_error! {
56 {
57 {
58 let _ = &$source; write!($writer, $string $(, $args)*)
60 }
61 } else {
62 {
63 write!($writer, concat!($string, ": {}") $(, $args)*, $source)
64 }
65 }
66 }
67 }
68 }
69}
70pub(crate) use write_err;
71
72#[derive(Debug, Clone, PartialEq, Eq)]
80pub enum DecodeVariableLengthBytesError {
81 InvalidChar(InvalidCharError),
83 OddLengthString(OddLengthStringError),
85}
86
87impl DecodeVariableLengthBytesError {
88 #[must_use]
102 #[inline]
103 pub fn offset(self, by_bytes: usize) -> Self {
104 use DecodeVariableLengthBytesError as E;
105
106 match self {
107 E::InvalidChar(e) => E::InvalidChar(e.offset(by_bytes)),
108 E::OddLengthString(e) => E::OddLengthString(e),
109 }
110 }
111}
112
113impl From<Infallible> for DecodeVariableLengthBytesError {
114 #[inline]
115 fn from(never: Infallible) -> Self { match never {} }
116}
117
118impl fmt::Display for DecodeVariableLengthBytesError {
119 #[inline]
120 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
121 use DecodeVariableLengthBytesError as E;
122
123 match *self {
124 E::InvalidChar(ref e) => write_err!(f, "failed to decode hex"; e),
125 E::OddLengthString(ref e) => write_err!(f, "failed to decode hex"; e),
126 }
127 }
128}
129
130if_std_error! {{
131 impl StdError for DecodeVariableLengthBytesError {
132 #[inline]
133 fn source(&self) -> Option<&(dyn StdError + 'static)> {
134 use DecodeVariableLengthBytesError as E;
135
136 match *self {
137 E::InvalidChar(ref e) => Some(e),
138 E::OddLengthString(ref e) => Some(e),
139 }
140 }
141 }
142}}
143
144impl From<InvalidCharError> for DecodeVariableLengthBytesError {
145 #[inline]
146 fn from(e: InvalidCharError) -> Self { Self::InvalidChar(e) }
147}
148
149impl From<OddLengthStringError> for DecodeVariableLengthBytesError {
150 #[inline]
151 fn from(e: OddLengthStringError) -> Self { Self::OddLengthString(e) }
152}
153
154#[derive(Debug, Clone, PartialEq, Eq)]
156pub struct InvalidCharError {
157 pub(crate) invalid: u8,
158 pub(crate) pos: usize,
159}
160
161impl From<Infallible> for InvalidCharError {
162 #[inline]
163 fn from(never: Infallible) -> Self { match never {} }
164}
165
166impl InvalidCharError {
167 #[inline]
169 pub(crate) fn invalid_char(&self) -> u8 { self.invalid }
170 #[inline]
172 pub fn pos(&self) -> usize { self.pos }
173
174 #[must_use]
192 #[inline]
193 pub fn offset(mut self, by_bytes: usize) -> Self {
194 self.pos += by_bytes;
195 self
196 }
197}
198
199impl fmt::Display for InvalidCharError {
202 #[inline]
203 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
204 struct Format<F: Fn(&mut fmt::Formatter<'_>) -> fmt::Result>(F);
210 impl<F: Fn(&mut fmt::Formatter<'_>) -> fmt::Result> fmt::Display for Format<F> {
211 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { self.0(f) }
212 }
213
214 let which;
216 let which: &dyn fmt::Display = match self.pos() {
217 0 => &"1st",
218 1 => &"2nd",
219 2 => &"3rd",
220 pos => {
221 which = Format(move |f| write!(f, "{}th", pos + 1));
222 &which
223 }
224 };
225
226 let chr_ascii;
228 let chr_non_ascii;
229
230 let invalid_char = self.invalid_char();
231 let chr: &dyn fmt::Display = if self.invalid_char().is_ascii() {
234 chr_ascii = Format(move |f| write!(f, "{:?}", invalid_char as char));
239 &chr_ascii
240 } else {
241 chr_non_ascii = Format(move |f| write!(f, "{:#02x}", invalid_char));
242 &chr_non_ascii
243 };
244
245 write!(f, "the {} character, {}, is not a valid hex digit", which, chr)
246 }
247}
248
249if_std_error! {{
250 impl StdError for InvalidCharError {}
251}}
252
253#[derive(Debug, Clone, PartialEq, Eq)]
255pub struct OddLengthStringError {
256 pub(crate) len: usize,
257}
258
259impl From<Infallible> for OddLengthStringError {
260 #[inline]
261 fn from(never: Infallible) -> Self { match never {} }
262}
263
264impl OddLengthStringError {
265 #[inline]
267 pub fn length(&self) -> usize { self.len }
268}
269
270impl fmt::Display for OddLengthStringError {
271 #[inline]
272 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
273 if self.length() == 1 {
274 write!(f, "the hex string is 1 byte long which is not an even number")
275 } else {
276 write!(f, "the hex string is {} bytes long which is not an even number", self.length())
277 }
278 }
279}
280
281if_std_error! {{
282 impl StdError for OddLengthStringError {}
283}}
284
285#[derive(Debug, Clone, PartialEq, Eq)]
290pub enum DecodeFixedLengthBytesError {
291 InvalidChar(InvalidCharError),
293 InvalidLength(InvalidLengthError),
295}
296
297impl DecodeFixedLengthBytesError {
298 #[must_use]
312 #[inline]
313 pub fn offset(self, by_bytes: usize) -> Self {
314 use DecodeFixedLengthBytesError as E;
315
316 match self {
317 E::InvalidChar(e) => E::InvalidChar(e.offset(by_bytes)),
318 E::InvalidLength(e) => E::InvalidLength(e),
319 }
320 }
321}
322
323impl From<Infallible> for DecodeFixedLengthBytesError {
324 #[inline]
325 fn from(never: Infallible) -> Self { match never {} }
326}
327
328impl fmt::Display for DecodeFixedLengthBytesError {
329 #[inline]
330 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
331 use DecodeFixedLengthBytesError as E;
332
333 match *self {
334 E::InvalidChar(ref e) => write_err!(f, "failed to parse hex"; e),
335 E::InvalidLength(ref e) => write_err!(f, "failed to parse hex"; e),
336 }
337 }
338}
339
340if_std_error! {{
341 impl StdError for DecodeFixedLengthBytesError {
342 #[inline]
343 fn source(&self) -> Option<&(dyn StdError + 'static)> {
344 use DecodeFixedLengthBytesError as E;
345
346 match *self {
347 E::InvalidChar(ref e) => Some(e),
348 E::InvalidLength(ref e) => Some(e),
349 }
350 }
351 }
352}}
353
354impl From<InvalidCharError> for DecodeFixedLengthBytesError {
355 #[inline]
356 fn from(e: InvalidCharError) -> Self { Self::InvalidChar(e) }
357}
358
359impl From<InvalidLengthError> for DecodeFixedLengthBytesError {
360 #[inline]
361 fn from(e: InvalidLengthError) -> Self { Self::InvalidLength(e) }
362}
363
364#[derive(Debug, Clone, PartialEq, Eq)]
366pub struct InvalidLengthError {
367 pub(crate) expected: usize,
369 pub(crate) invalid: usize,
371}
372
373impl From<Infallible> for InvalidLengthError {
374 #[inline]
375 fn from(never: Infallible) -> Self { match never {} }
376}
377
378impl InvalidLengthError {
379 #[inline]
384 pub fn expected_length(&self) -> usize { self.expected }
385
386 #[inline]
391 pub fn invalid_length(&self) -> usize { self.invalid }
392}
393
394impl fmt::Display for InvalidLengthError {
395 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
396 write!(
397 f,
398 "the hex string is {} bytes long but exactly {} bytes were required",
400 self.invalid_length(),
401 self.expected_length()
402 )
403 }
404}
405
406if_std_error! {{
407 impl StdError for InvalidLengthError {}
408}}
409
410#[cfg(test)]
411#[cfg(feature = "std")]
412mod tests {
413 use super::*;
414 use crate::{decode_to_array, decode_to_vec};
415
416 fn check_source<T: std::error::Error>(error: &T) {
417 assert!(error.source().is_some());
418 }
419
420 #[cfg(feature = "alloc")]
421 #[test]
422 fn invalid_char_error() {
423 let result = decode_to_vec("12G4");
424 let error = result.unwrap_err();
425 if let DecodeVariableLengthBytesError::InvalidChar(e) = error {
426 assert!(!format!("{}", e).is_empty());
427 assert_eq!(e.invalid_char(), b'G');
428 assert_eq!(e.pos(), 2);
429 } else {
430 panic!("Expected InvalidCharError");
431 }
432 }
433
434 #[cfg(feature = "alloc")]
435 #[test]
436 fn odd_length_string_error() {
437 let result = decode_to_vec("123");
438 let error = result.unwrap_err();
439 assert!(!format!("{}", error).is_empty());
440 check_source(&error);
441 if let DecodeVariableLengthBytesError::OddLengthString(e) = error {
442 assert!(!format!("{}", e).is_empty());
443 assert_eq!(e.length(), 3);
444 } else {
445 panic!("Expected OddLengthStringError");
446 }
447 }
448
449 #[test]
450 fn invalid_length_error() {
451 let result = decode_to_array::<4>("123");
452 let error = result.unwrap_err();
453 assert!(!format!("{}", error).is_empty());
454 check_source(&error);
455 if let DecodeFixedLengthBytesError::InvalidLength(e) = error {
456 assert!(!format!("{}", e).is_empty());
457 assert_eq!(e.expected_length(), 8);
458 assert_eq!(e.invalid_length(), 3);
459 } else {
460 panic!("Expected InvalidLengthError");
461 }
462 }
463
464 #[test]
465 fn to_bytes_error() {
466 let error =
467 DecodeVariableLengthBytesError::OddLengthString(OddLengthStringError { len: 7 });
468 assert!(!format!("{}", error).is_empty());
469 check_source(&error);
470 }
471
472 #[test]
473 fn to_array_error() {
474 let error = DecodeFixedLengthBytesError::InvalidLength(InvalidLengthError {
475 expected: 8,
476 invalid: 7,
477 });
478 assert!(!format!("{}", error).is_empty());
479 check_source(&error);
480 }
481}