hex_conservative/
error.rs

1// SPDX-License-Identifier: CC0-1.0
2
3//! Error code for the `hex-conservative` crate.
4
5use core::fmt;
6
7use crate::write_err;
8
9/// Formats error.
10///
11/// If `std` feature is OFF appends error source (delimited by `: `). We do this because
12/// `e.source()` is only available in std builds, without this macro the error source is lost for
13/// no-std builds.
14#[macro_export]
15macro_rules! write_err {
16    ($writer:expr, $string:literal $(, $args:expr)*; $source:expr) => {
17        {
18            #[cfg(feature = "std")]
19            {
20                let _ = &$source;   // Prevents clippy warnings.
21                write!($writer, $string $(, $args)*)
22            }
23            #[cfg(not(feature = "std"))]
24            {
25                write!($writer, concat!($string, ": {}") $(, $args)*, $source)
26            }
27        }
28    }
29}
30
31/// Hex decoding error.
32#[derive(Debug, Clone, PartialEq, Eq)]
33pub enum HexToBytesError {
34    /// Non-hexadecimal character.
35    InvalidChar(InvalidCharError),
36    /// Purported hex string had odd length.
37    OddLengthString(OddLengthStringError),
38}
39
40impl fmt::Display for HexToBytesError {
41    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
42        use HexToBytesError::*;
43
44        match *self {
45            InvalidChar(ref e) => write_err!(f, "invalid char, failed to create bytes from hex"; e),
46            OddLengthString(ref e) =>
47                write_err!(f, "odd length, failed to create bytes from hex"; e),
48        }
49    }
50}
51
52#[cfg(feature = "std")]
53impl std::error::Error for HexToBytesError {
54    fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
55        use HexToBytesError::*;
56
57        match *self {
58            InvalidChar(ref e) => Some(e),
59            OddLengthString(ref e) => Some(e),
60        }
61    }
62}
63
64impl From<InvalidCharError> for HexToBytesError {
65    #[inline]
66    fn from(e: InvalidCharError) -> Self { Self::InvalidChar(e) }
67}
68
69impl From<OddLengthStringError> for HexToBytesError {
70    #[inline]
71    fn from(e: OddLengthStringError) -> Self { Self::OddLengthString(e) }
72}
73
74/// Invalid hex character.
75#[derive(Debug, Clone, PartialEq, Eq)]
76pub struct InvalidCharError {
77    pub(crate) invalid: u8,
78    pub(crate) pos: usize,
79}
80
81impl InvalidCharError {
82    /// Returns the invalid character byte.
83    pub fn invalid_char(&self) -> u8 { self.invalid }
84    /// Returns the position of the invalid character byte.
85    pub fn pos(&self) -> usize { self.pos }
86}
87
88impl fmt::Display for InvalidCharError {
89    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
90        write!(f, "invalid hex char {} at pos {}", self.invalid, self.pos)
91    }
92}
93
94#[cfg(feature = "std")]
95impl std::error::Error for InvalidCharError {
96    fn source(&self) -> Option<&(dyn std::error::Error + 'static)> { None }
97}
98
99/// Purported hex string had odd length.
100#[derive(Debug, Clone, PartialEq, Eq)]
101pub struct OddLengthStringError {
102    pub(crate) len: usize,
103}
104
105impl OddLengthStringError {
106    /// Returns the odd length of the input string.
107    pub fn length(&self) -> usize { self.len }
108}
109
110impl fmt::Display for OddLengthStringError {
111    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
112        write!(f, "odd hex string length {}", self.len)
113    }
114}
115
116#[cfg(feature = "std")]
117impl std::error::Error for OddLengthStringError {
118    fn source(&self) -> Option<&(dyn std::error::Error + 'static)> { None }
119}
120
121/// Hex decoding error.
122#[derive(Debug, Clone, PartialEq, Eq)]
123pub enum HexToArrayError {
124    /// Non-hexadecimal character.
125    InvalidChar(InvalidCharError),
126    /// Tried to parse fixed-length hash from a string with the wrong length.
127    InvalidLength(InvalidLengthError),
128}
129
130impl fmt::Display for HexToArrayError {
131    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
132        use HexToArrayError::*;
133
134        match *self {
135            InvalidChar(ref e) => crate::write_err!(f, "failed to parse hex digit"; e),
136            InvalidLength(ref e) => write_err!(f, "failed to parse hex"; e),
137        }
138    }
139}
140
141#[cfg(feature = "std")]
142impl std::error::Error for HexToArrayError {
143    fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
144        use HexToArrayError::*;
145
146        match *self {
147            InvalidChar(ref e) => Some(e),
148            InvalidLength(ref e) => Some(e),
149        }
150    }
151}
152
153impl From<InvalidCharError> for HexToArrayError {
154    #[inline]
155    fn from(e: InvalidCharError) -> Self { Self::InvalidChar(e) }
156}
157
158impl From<InvalidLengthError> for HexToArrayError {
159    #[inline]
160    fn from(e: InvalidLengthError) -> Self { Self::InvalidLength(e) }
161}
162
163/// Tried to parse fixed-length hash from a string with the wrong length.
164#[derive(Debug, Clone, PartialEq, Eq)]
165#[non_exhaustive]
166pub struct InvalidLengthError {
167    /// The expected length.
168    pub expected: usize,
169    /// The invalid length.
170    pub invalid: usize,
171}
172
173impl fmt::Display for InvalidLengthError {
174    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
175        write!(f, "invilad hex string length {} (expected {})", self.invalid, self.expected)
176    }
177}
178
179#[cfg(feature = "std")]
180impl std::error::Error for InvalidLengthError {
181    fn source(&self) -> Option<&(dyn std::error::Error + 'static)> { None }
182}