Skip to content

Commit dee6b08

Browse files
committed
Hide all errors
Hide the internals of all errors by wrapping enum variant internals in structs.
1 parent 881c098 commit dee6b08

File tree

4 files changed

+117
-28
lines changed

4 files changed

+117
-28
lines changed

examples/custom.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -117,7 +117,7 @@ impl<'a> fmt::UpperHex for DisplayALittleBitHexy<'a> {
117117
}
118118

119119
/// Example Error.
120-
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
120+
#[derive(Debug, Clone, PartialEq, Eq)]
121121
pub enum Error {
122122
/// Conversion error while parsing hex string.
123123
Conversion(HexToBytesError),

src/error.rs

Lines changed: 84 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@
22

33
use core::fmt;
44

5+
use crate::write_err;
6+
57
/// Formats error.
68
///
79
/// If `std` feature is OFF appends error source (delimited by `: `). We do this because
@@ -28,18 +30,19 @@ macro_rules! write_err {
2830
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
2931
pub enum HexToBytesError {
3032
/// Non-hexadecimal character.
31-
InvalidChar(u8),
33+
InvalidChar(InvalidCharError),
3234
/// Purported hex string had odd length.
33-
OddLengthString(usize),
35+
OddLengthString(OddLengthStringError),
3436
}
3537

3638
impl fmt::Display for HexToBytesError {
3739
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
3840
use HexToBytesError::*;
3941

4042
match *self {
41-
InvalidChar(ch) => write!(f, "invalid hex character {}", ch),
42-
OddLengthString(ell) => write!(f, "odd hex string length {}", ell),
43+
InvalidChar(ref e) => write_err!(f, "invalid char, failed to create bytes from hex"; e),
44+
OddLengthString(ref e) =>
45+
write_err!(f, "odd length, failed to create bytes from hex"; e),
4346
}
4447
}
4548
}
@@ -49,29 +52,75 @@ impl std::error::Error for HexToBytesError {
4952
fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
5053
use HexToBytesError::*;
5154

52-
match self {
53-
InvalidChar(_) | OddLengthString(_) => None,
55+
match *self {
56+
InvalidChar(ref e) => Some(e),
57+
OddLengthString(ref e) => Some(e),
5458
}
5559
}
5660
}
5761

58-
/// Hex decoding error.
62+
impl From<InvalidCharError> for HexToBytesError {
63+
#[inline]
64+
fn from(e: InvalidCharError) -> Self { Self::InvalidChar(e) }
65+
}
66+
67+
impl From<OddLengthStringError> for HexToBytesError {
68+
#[inline]
69+
fn from(e: OddLengthStringError) -> Self { Self::OddLengthString(e) }
70+
}
71+
72+
/// Invalid hex character.
5973
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
74+
pub struct InvalidCharError {
75+
pub(crate) invalid: u8,
76+
}
77+
78+
impl fmt::Display for InvalidCharError {
79+
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
80+
write!(f, "invalid hex char {}", self.invalid)
81+
}
82+
}
83+
84+
#[cfg(feature = "std")]
85+
impl std::error::Error for InvalidCharError {
86+
fn source(&self) -> Option<&(dyn std::error::Error + 'static)> { None }
87+
}
88+
89+
/// Purported hex string had odd length.
90+
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
91+
pub struct OddLengthStringError {
92+
pub(crate) len: usize,
93+
}
94+
95+
impl fmt::Display for OddLengthStringError {
96+
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
97+
write!(f, "odd hex string length {}", self.len)
98+
}
99+
}
100+
101+
#[cfg(feature = "std")]
102+
impl std::error::Error for OddLengthStringError {
103+
fn source(&self) -> Option<&(dyn std::error::Error + 'static)> { None }
104+
}
105+
106+
/// Hex decoding error.
107+
#[derive(Debug, Clone, PartialEq, Eq)]
60108
pub enum HexToArrayError {
61109
/// Conversion error while parsing hex string.
62110
Conversion(HexToBytesError),
63111
/// Tried to parse fixed-length hash from a string with the wrong length (got, want).
64-
InvalidLength(usize, usize),
112+
InvalidLength(InvalidLengthError),
65113
}
66114

67115
impl fmt::Display for HexToArrayError {
68116
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
69117
use HexToArrayError::*;
70118

71119
match *self {
72-
Conversion(ref e) => crate::write_err!(f, "conversion error"; e),
73-
InvalidLength(got, want) =>
74-
write!(f, "bad hex string length {} (expected {})", got, want),
120+
Conversion(ref e) =>
121+
crate::write_err!(f, "conversion error, failed to create array from hex"; e),
122+
InvalidLength(ref e) =>
123+
write_err!(f, "invalid length, failed to create array from hex"; e),
75124
}
76125
}
77126
}
@@ -83,7 +132,7 @@ impl std::error::Error for HexToArrayError {
83132

84133
match *self {
85134
Conversion(ref e) => Some(e),
86-
InvalidLength(_, _) => None,
135+
InvalidLength(ref e) => Some(e),
87136
}
88137
}
89138
}
@@ -92,3 +141,26 @@ impl From<HexToBytesError> for HexToArrayError {
92141
#[inline]
93142
fn from(e: HexToBytesError) -> Self { Self::Conversion(e) }
94143
}
144+
145+
impl From<InvalidLengthError> for HexToArrayError {
146+
#[inline]
147+
fn from(e: InvalidLengthError) -> Self { Self::InvalidLength(e) }
148+
}
149+
150+
/// Tried to parse fixed-length hash from a string with the wrong length.
151+
#[derive(Debug, Clone, PartialEq, Eq)]
152+
pub struct InvalidLengthError {
153+
pub(crate) expected: usize,
154+
pub(crate) got: usize,
155+
}
156+
157+
impl fmt::Display for InvalidLengthError {
158+
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
159+
write!(f, "bad hex string length {} (expected {})", self.got, self.expected)
160+
}
161+
}
162+
163+
#[cfg(feature = "std")]
164+
impl std::error::Error for InvalidLengthError {
165+
fn source(&self) -> Option<&(dyn std::error::Error + 'static)> { None }
166+
}

src/iter.rs

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,8 @@ use std::io;
1010
#[cfg(all(feature = "core2", not(feature = "std")))]
1111
use core2::io;
1212

13-
use crate::parse::HexToBytesError;
13+
#[rustfmt::skip] // Keep public re-exports separate.
14+
pub use crate::error::{HexToBytesError, OddLengthStringError, InvalidCharError};
1415

1516
/// Iterator over a hex-encoded string slice which decodes hex and yields bytes.
1617
pub struct HexToBytesIter<'a> {
@@ -33,7 +34,7 @@ impl<'a> HexToBytesIter<'a> {
3334
#[inline]
3435
pub fn new(s: &'a str) -> Result<HexToBytesIter<'a>, HexToBytesError> {
3536
if s.len() % 2 != 0 {
36-
Err(HexToBytesError::OddLengthString(s.len()))
37+
Err(HexToBytesError::OddLengthString(OddLengthStringError { len: s.len() }))
3738
} else {
3839
Ok(HexToBytesIter { iter: s.bytes() })
3940
}
@@ -93,8 +94,12 @@ impl<'a> io::Read for HexToBytesIter<'a> {
9394

9495
/// `hi` and `lo` are bytes representing hex characters.
9596
fn hex_chars_to_byte(hi: u8, lo: u8) -> Result<u8, HexToBytesError> {
96-
let hih = (hi as char).to_digit(16).ok_or(HexToBytesError::InvalidChar(hi))?;
97-
let loh = (lo as char).to_digit(16).ok_or(HexToBytesError::InvalidChar(lo))?;
97+
let hih = (hi as char)
98+
.to_digit(16)
99+
.ok_or(HexToBytesError::InvalidChar(InvalidCharError { invalid: hi }))?;
100+
let loh = (lo as char)
101+
.to_digit(16)
102+
.ok_or(HexToBytesError::InvalidChar(InvalidCharError { invalid: lo }))?;
98103

99104
let ret = (hih << 4) + loh;
100105
Ok(ret as u8)

src/parse.rs

Lines changed: 23 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ use crate::alloc::vec::Vec;
99
use crate::iter::HexToBytesIter;
1010

1111
#[rustfmt::skip] // Keep public re-exports separate.
12-
pub use crate::error::{HexToBytesError, HexToArrayError};
12+
pub use crate::error::{HexToBytesError, HexToArrayError, InvalidLengthError, OddLengthStringError, InvalidCharError};
1313

1414
/// Trait for objects that can be deserialized from hex strings.
1515
pub trait FromHex: Sized {
@@ -58,7 +58,10 @@ macro_rules! impl_fromhex_array {
5858
}
5959
Ok(ret)
6060
} else {
61-
Err(HexToArrayError::InvalidLength(2 * $len, 2 * iter.len()))
61+
Err(HexToArrayError::InvalidLength(InvalidLengthError {
62+
expected: 2 * $len,
63+
got: 2 * iter.len(),
64+
}))
6265
}
6366
}
6467
}
@@ -93,21 +96,28 @@ mod tests {
9396
#[test]
9497
#[cfg(feature = "alloc")]
9598
fn hex_error() {
96-
use HexToBytesError::*;
97-
9899
let oddlen = "0123456789abcdef0";
99100
let badchar1 = "Z123456789abcdef";
100101
let badchar2 = "012Y456789abcdeb";
101102
let badchar3 = "«23456789abcdef";
102103

103-
assert_eq!(Vec::<u8>::from_hex(oddlen), Err(OddLengthString(17)));
104+
assert_eq!(Vec::<u8>::from_hex(oddlen), Err(OddLengthStringError { len: 17 }.into()));
104105
assert_eq!(
105106
<[u8; 4]>::from_hex(oddlen),
106-
Err(HexToArrayError::Conversion(OddLengthString(17)))
107+
Err(HexToBytesError::OddLengthString(OddLengthStringError { len: 17 }).into())
108+
);
109+
assert_eq!(
110+
Vec::<u8>::from_hex(badchar1),
111+
Err(HexToBytesError::InvalidChar(InvalidCharError { invalid: b'Z' }).into())
112+
);
113+
assert_eq!(
114+
Vec::<u8>::from_hex(badchar2),
115+
Err(HexToBytesError::InvalidChar(InvalidCharError { invalid: b'Y' }).into())
116+
);
117+
assert_eq!(
118+
Vec::<u8>::from_hex(badchar3),
119+
Err(HexToBytesError::InvalidChar(InvalidCharError { invalid: 194 }).into())
107120
);
108-
assert_eq!(Vec::<u8>::from_hex(badchar1), Err(InvalidChar(b'Z')));
109-
assert_eq!(Vec::<u8>::from_hex(badchar2), Err(InvalidChar(b'Y')));
110-
assert_eq!(Vec::<u8>::from_hex(badchar3), Err(InvalidChar(194)));
111121
}
112122

113123
#[test]
@@ -117,9 +127,11 @@ mod tests {
117127
}
118128
#[test]
119129
fn hex_to_array_error() {
120-
use HexToArrayError::*;
121130
let len_sixteen = "0123456789abcdef";
122-
assert_eq!(<[u8; 4]>::from_hex(len_sixteen), Err(InvalidLength(8, 16)));
131+
assert_eq!(
132+
<[u8; 4]>::from_hex(len_sixteen),
133+
Err(InvalidLengthError { expected: 8, got: 16 }.into())
134+
)
123135
}
124136

125137
#[test]

0 commit comments

Comments
 (0)