Skip to content

Commit af04208

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

File tree

4 files changed

+108
-28
lines changed

4 files changed

+108
-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: 88 additions & 13 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
@@ -25,21 +27,22 @@ macro_rules! write_err {
2527
}
2628

2729
/// Hex decoding error.
28-
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
30+
#[derive(Debug, 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,77 @@ 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

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.
73+
#[derive(Debug, Clone, PartialEq, Eq)]
74+
#[non_exhaustive]
75+
pub struct InvalidCharError {
76+
pub(crate) invalid: u8,
77+
}
78+
79+
impl fmt::Display for InvalidCharError {
80+
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
81+
write!(f, "invalid hex char {}", self.invalid)
82+
}
83+
}
84+
85+
#[cfg(feature = "std")]
86+
impl std::error::Error for InvalidCharError {
87+
fn source(&self) -> Option<&(dyn std::error::Error + 'static)> { None }
88+
}
89+
90+
/// Purported hex string had odd length.
91+
#[derive(Debug, Clone, PartialEq, Eq)]
92+
#[non_exhaustive]
93+
pub struct OddLengthStringError {
94+
pub(crate) len: usize,
95+
}
96+
97+
impl fmt::Display for OddLengthStringError {
98+
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
99+
write!(f, "odd hex string length {}", self.len)
100+
}
101+
}
102+
103+
#[cfg(feature = "std")]
104+
impl std::error::Error for OddLengthStringError {
105+
fn source(&self) -> Option<&(dyn std::error::Error + 'static)> { None }
106+
}
107+
58108
/// Hex decoding error.
59-
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
109+
#[derive(Debug, Clone, PartialEq, Eq)]
60110
pub enum HexToArrayError {
61111
/// Conversion error while parsing hex string.
62112
Conversion(HexToBytesError),
63113
/// Tried to parse fixed-length hash from a string with the wrong length (got, want).
64-
InvalidLength(usize, usize),
114+
InvalidLength(InvalidLengthError),
65115
}
66116

67117
impl fmt::Display for HexToArrayError {
68118
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
69119
use HexToArrayError::*;
70120

71121
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),
122+
Conversion(ref e) =>
123+
crate::write_err!(f, "conversion error, failed to create array from hex"; e),
124+
InvalidLength(ref e) =>
125+
write_err!(f, "invalid length, failed to create array from hex"; e),
75126
}
76127
}
77128
}
@@ -83,7 +134,7 @@ impl std::error::Error for HexToArrayError {
83134

84135
match *self {
85136
Conversion(ref e) => Some(e),
86-
InvalidLength(_, _) => None,
137+
InvalidLength(ref e) => Some(e),
87138
}
88139
}
89140
}
@@ -92,3 +143,27 @@ impl From<HexToBytesError> for HexToArrayError {
92143
#[inline]
93144
fn from(e: HexToBytesError) -> Self { Self::Conversion(e) }
94145
}
146+
147+
impl From<InvalidLengthError> for HexToArrayError {
148+
#[inline]
149+
fn from(e: InvalidLengthError) -> Self { Self::InvalidLength(e) }
150+
}
151+
152+
/// Tried to parse fixed-length hash from a string with the wrong length.
153+
#[derive(Debug, Clone, PartialEq, Eq)]
154+
#[non_exhaustive]
155+
pub struct InvalidLengthError {
156+
pub(crate) expected: usize,
157+
pub(crate) got: usize,
158+
}
159+
160+
impl fmt::Display for InvalidLengthError {
161+
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
162+
write!(f, "bad hex string length {} (expected {})", self.got, self.expected)
163+
}
164+
}
165+
166+
#[cfg(feature = "std")]
167+
impl std::error::Error for InvalidLengthError {
168+
fn source(&self) -> Option<&(dyn std::error::Error + 'static)> { None }
169+
}

src/iter.rs

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

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

1518
/// Iterator over a hex-encoded string slice which decodes hex and yields bytes.
1619
pub struct HexToBytesIter<'a> {
@@ -33,7 +36,7 @@ impl<'a> HexToBytesIter<'a> {
3336
#[inline]
3437
pub fn new(s: &'a str) -> Result<HexToBytesIter<'a>, HexToBytesError> {
3538
if s.len() % 2 != 0 {
36-
Err(HexToBytesError::OddLengthString(s.len()))
39+
Err(OddLengthStringError { len: s.len() }.into())
3740
} else {
3841
Ok(HexToBytesIter { iter: s.bytes() })
3942
}
@@ -93,8 +96,8 @@ impl<'a> io::Read for HexToBytesIter<'a> {
9396

9497
/// `hi` and `lo` are bytes representing hex characters.
9598
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))?;
99+
let hih = (hi as char).to_digit(16).ok_or(InvalidCharError { invalid: hi })?;
100+
let loh = (lo as char).to_digit(16).ok_or(InvalidCharError { invalid: lo })?;
98101

99102
let ret = (hih << 4) + loh;
100103
Ok(ret as u8)

src/parse.rs

Lines changed: 12 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ use core::{fmt, str};
66

77
#[cfg(all(feature = "alloc", not(feature = "std")))]
88
use crate::alloc::vec::Vec;
9+
use crate::error::InvalidLengthError;
910
use crate::iter::HexToBytesIter;
1011

1112
#[rustfmt::skip] // Keep public re-exports separate.
@@ -58,7 +59,7 @@ macro_rules! impl_fromhex_array {
5859
}
5960
Ok(ret)
6061
} else {
61-
Err(HexToArrayError::InvalidLength(2 * $len, 2 * iter.len()))
62+
Err(InvalidLengthError { expected: 2 * $len, got: 2 * iter.len() }.into())
6263
}
6364
}
6465
}
@@ -89,25 +90,24 @@ impl_fromhex_array!(512);
8990
mod tests {
9091
use super::*;
9192
use crate::display::DisplayHex;
93+
use crate::error::{InvalidCharError, InvalidLengthError, OddLengthStringError};
9294

9395
#[test]
9496
#[cfg(feature = "alloc")]
9597
fn hex_error() {
96-
use HexToBytesError::*;
97-
9898
let oddlen = "0123456789abcdef0";
9999
let badchar1 = "Z123456789abcdef";
100100
let badchar2 = "012Y456789abcdeb";
101101
let badchar3 = "«23456789abcdef";
102102

103-
assert_eq!(Vec::<u8>::from_hex(oddlen), Err(OddLengthString(17)));
103+
assert_eq!(Vec::<u8>::from_hex(oddlen), Err(OddLengthStringError { len: 17 }.into()));
104104
assert_eq!(
105105
<[u8; 4]>::from_hex(oddlen),
106-
Err(HexToArrayError::Conversion(OddLengthString(17)))
106+
Err(HexToBytesError::OddLengthString(OddLengthStringError { len: 17 }).into())
107107
);
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)));
108+
assert_eq!(Vec::<u8>::from_hex(badchar1), Err(InvalidCharError { invalid: b'Z' }.into()));
109+
assert_eq!(Vec::<u8>::from_hex(badchar2), Err(InvalidCharError { invalid: b'Y' }.into()));
110+
assert_eq!(Vec::<u8>::from_hex(badchar3), Err(InvalidCharError { invalid: 194 }.into()));
111111
}
112112

113113
#[test]
@@ -117,9 +117,11 @@ mod tests {
117117
}
118118
#[test]
119119
fn hex_to_array_error() {
120-
use HexToArrayError::*;
121120
let len_sixteen = "0123456789abcdef";
122-
assert_eq!(<[u8; 4]>::from_hex(len_sixteen), Err(InvalidLength(8, 16)));
121+
assert_eq!(
122+
<[u8; 4]>::from_hex(len_sixteen),
123+
Err(InvalidLengthError { expected: 8, got: 16 }.into())
124+
)
123125
}
124126

125127
#[test]

0 commit comments

Comments
 (0)