Skip to content
This repository was archived by the owner on Nov 30, 2022. It is now read-only.

Commit b4808ca

Browse files
committed
Add custom error type by way of FromHexRestricted
Add an additional type `FromHexRestricted` that enables users to return a custom error type.
1 parent a7e3ff6 commit b4808ca

File tree

1 file changed

+77
-30
lines changed

1 file changed

+77
-30
lines changed

src/hex.rs

Lines changed: 77 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,8 @@ use std::io;
2626
use core2::io;
2727

2828
use core::{fmt, str};
29+
use core::convert::Infallible;
30+
2931
use crate::Hash;
3032

3133
/// Hex decoding error.
@@ -58,15 +60,66 @@ pub trait ToHex {
5860
}
5961

6062
/// Trait for objects that can be deserialized from hex strings.
61-
pub trait FromHex: Sized {
63+
///
64+
/// Implement this trait if the `Error` enum is suitable for returning all your errors, if you need
65+
/// an additional custom error consider implementing `FromHexRestricted`.
66+
pub trait FromHex: FromHexRestricted<CustomError = Infallible> + Sized {
6267
/// Produces an object from a byte iterator.
6368
fn from_byte_iter<I>(iter: I) -> Result<Self, Error>
6469
where
6570
I: Iterator<Item = Result<u8, Error>> + ExactSizeIterator + DoubleEndedIterator;
6671

6772
/// Produces an object from a hex string.
6873
fn from_hex(s: &str) -> Result<Self, Error> {
69-
Self::from_byte_iter(HexIterator::new(s)?)
74+
<Self as FromHex>::from_byte_iter(HexIterator::new(s)?)
75+
}
76+
}
77+
78+
/// Enables users of the library to return a custom error when implementing the `FromHexRestricted` trait.
79+
pub enum MaybeCustomError<E> {
80+
/// Wraps the custom error `E`.
81+
Custom(E),
82+
/// Wraps the [`hex::Error`].
83+
Encoding(Error),
84+
}
85+
86+
impl<E: fmt::Display> fmt::Display for MaybeCustomError<E> {
87+
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
88+
match &*self {
89+
MaybeCustomError::Custom(e) => write!(f, "{}", e),
90+
MaybeCustomError::Encoding(e) => write!(f, "{}", e),
91+
}
92+
}
93+
}
94+
95+
/// Trait for objects that can be deserialized from hex strings.
96+
///
97+
/// Implement this trait if `Error` is not enough and you need an additional custom error. An
98+
/// implementation of this trait is automatically added for any types that implement `FromHex`.
99+
pub trait FromHexRestricted: Sized {
100+
/// The type returned inside of `MaybeCustomError::Custom`.
101+
type CustomError;
102+
103+
/// Produces an object from a byte iterator.
104+
fn from_byte_iter<I>(iter: I) -> Result<Self, MaybeCustomError<Self::CustomError>>
105+
where
106+
I: Iterator<Item = Result<u8, Error>> + ExactSizeIterator + DoubleEndedIterator;
107+
108+
/// Produces an object from a hex string.
109+
fn from_hex(s: &str) -> Result<Self, MaybeCustomError<Self::CustomError>> {
110+
Self::from_byte_iter(HexIterator::new(s).map_err(|e| MaybeCustomError::Encoding(e))?)
111+
}
112+
}
113+
114+
/// Implements `FromHexRestricted` for types that only error during encoding i.e., no custom error.
115+
impl<T: FromHex> FromHexRestricted for T {
116+
type CustomError = Infallible;
117+
118+
fn from_byte_iter<I>(iter: I) -> Result<Self, MaybeCustomError<Infallible>>
119+
where
120+
I: Iterator<Item = Result<u8, Error>> + ExactSizeIterator + DoubleEndedIterator
121+
{
122+
<T as FromHex>::from_byte_iter(iter).map_err(|e| MaybeCustomError::Encoding(e))
70123
}
71124
}
72125

@@ -84,11 +137,12 @@ impl<T: Hash> FromHex for T {
84137
where
85138
I: Iterator<Item = Result<u8, Error>> + ExactSizeIterator + DoubleEndedIterator,
86139
{
87-
let inner = if Self::DISPLAY_BACKWARD {
88-
T::Inner::from_byte_iter(iter.rev())?
140+
let inner;
141+
if Self::DISPLAY_BACKWARD {
142+
inner = <<T as Hash>::Inner as FromHex>::from_byte_iter(iter.rev())?;
89143
} else {
90-
T::Inner::from_byte_iter(iter)?
91-
};
144+
inner = <<T as Hash>::Inner as FromHex>::from_byte_iter(iter)?;
145+
}
92146
Ok(Hash::from_inner(inner))
93147
}
94148
}
@@ -373,30 +427,23 @@ mod tests {
373427
let badchar2 = "012Y456789abcdeb";
374428
let badchar3 = "«23456789abcdef";
375429

376-
assert_eq!(
377-
Vec::<u8>::from_hex(oddlen),
378-
Err(Error::OddLengthString(17))
379-
);
380-
assert_eq!(
381-
<[u8; 4]>::from_hex(oddlen),
382-
Err(Error::OddLengthString(17))
383-
);
384-
assert_eq!(
385-
<[u8; 8]>::from_hex(oddlen),
386-
Err(Error::OddLengthString(17))
387-
);
388-
assert_eq!(
389-
Vec::<u8>::from_hex(badchar1),
390-
Err(Error::InvalidChar(b'Z'))
391-
);
392-
assert_eq!(
393-
Vec::<u8>::from_hex(badchar2),
394-
Err(Error::InvalidChar(b'Y'))
395-
);
396-
assert_eq!(
397-
Vec::<u8>::from_hex(badchar3),
398-
Err(Error::InvalidChar(194))
399-
);
430+
let res: Result<Vec<u8>, Error> = FromHex::from_hex(oddlen);
431+
assert_eq!(res, Err(Error::OddLengthString(17)));
432+
433+
let res: Result<[u8; 4], Error> = FromHex::from_hex(oddlen);
434+
assert_eq!(res, Err(Error::OddLengthString(17)));
435+
436+
let res: Result<[u8; 8], Error> = FromHex::from_hex(oddlen);
437+
assert_eq!(res, Err(Error::OddLengthString(17)));
438+
439+
let res: Result<Vec<u8>, Error> = FromHex::from_hex(badchar1);
440+
assert_eq!(res, Err(Error::InvalidChar(b'Z')));
441+
442+
let res: Result<Vec<u8>, Error> = FromHex::from_hex(badchar2);
443+
assert_eq!(res, Err(Error::InvalidChar(b'Y')));
444+
445+
let res: Result<Vec<u8>, Error> = FromHex::from_hex(badchar3);
446+
assert_eq!(res, Err(Error::InvalidChar(194)));
400447
}
401448
}
402449

0 commit comments

Comments
 (0)