hex_conservative/
parse.rs1use core::{fmt, str};
6
7use arrayvec::ArrayVec;
8
9#[cfg(all(feature = "alloc", not(feature = "std")))]
10use crate::alloc::vec::Vec;
11use crate::error::InvalidLengthError;
12use crate::iter::HexToBytesIter;
13
14#[rustfmt::skip] pub use crate::error::{HexToBytesError, HexToArrayError};
16
17pub trait FromHex: Sized {
19 type Error: Sized + fmt::Debug + fmt::Display;
21
22 fn from_hex(s: &str) -> Result<Self, Self::Error>;
24}
25
26#[cfg(any(test, feature = "std", feature = "alloc"))]
27impl FromHex for Vec<u8> {
28 type Error = HexToBytesError;
29
30 fn from_hex(s: &str) -> Result<Self, Self::Error> {
31 HexToBytesIter::new(s)?.map(|result| result.map_err(Into::into)).collect()
32 }
33}
34
35impl<const LEN: usize> FromHex for [u8; LEN] {
36 type Error = HexToArrayError;
37
38 fn from_hex(s: &str) -> Result<Self, Self::Error> {
39 if s.len() == LEN * 2 {
40 let mut ret = ArrayVec::<u8, LEN>::new();
41 for byte in HexToBytesIter::new_unchecked(s) {
43 ret.push(byte?);
44 }
45 Ok(ret.into_inner().expect("inner is full"))
46 } else {
47 Err(InvalidLengthError { invalid: s.len(), expected: 2 * LEN }.into())
48 }
49 }
50}
51
52#[cfg(test)]
53mod tests {
54 use super::*;
55 use crate::display::DisplayHex;
56
57 #[test]
58 #[cfg(feature = "alloc")]
59 fn hex_error() {
60 use crate::error::{InvalidCharError, OddLengthStringError};
61
62 let oddlen = "0123456789abcdef0";
63 let badchar1 = "Z123456789abcdef";
64 let badchar2 = "012Y456789abcdeb";
65 let badchar3 = "«23456789abcdef";
66
67 assert_eq!(Vec::<u8>::from_hex(oddlen), Err(OddLengthStringError { len: 17 }.into()));
68 assert_eq!(
69 <[u8; 4]>::from_hex(oddlen),
70 Err(InvalidLengthError { invalid: 17, expected: 8 }.into())
71 );
72 assert_eq!(Vec::<u8>::from_hex(badchar1), Err(InvalidCharError { invalid: b'Z' }.into()));
73 assert_eq!(Vec::<u8>::from_hex(badchar2), Err(InvalidCharError { invalid: b'Y' }.into()));
74 assert_eq!(Vec::<u8>::from_hex(badchar3), Err(InvalidCharError { invalid: 194 }.into()));
75 }
76
77 #[test]
78 fn hex_to_array() {
79 let len_sixteen = "0123456789abcdef";
80 assert!(<[u8; 8]>::from_hex(len_sixteen).is_ok());
81 }
82
83 #[test]
84 fn hex_to_array_error() {
85 let len_sixteen = "0123456789abcdef";
86 assert_eq!(
87 <[u8; 4]>::from_hex(len_sixteen),
88 Err(InvalidLengthError { invalid: 16, expected: 8 }.into())
89 )
90 }
91
92 #[test]
93 fn mixed_case() {
94 let s = "DEADbeef0123";
95 let want_lower = "deadbeef0123";
96 let want_upper = "DEADBEEF0123";
97
98 let v = Vec::<u8>::from_hex(s).expect("valid hex");
99 assert_eq!(format!("{:x}", v.as_hex()), want_lower);
100 assert_eq!(format!("{:X}", v.as_hex()), want_upper);
101 }
102}