@@ -26,6 +26,8 @@ use std::io;
2626use core2:: io;
2727
2828use core:: { fmt, str} ;
29+ use core:: convert:: Infallible ;
30+
2931use 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