1#[cfg(feature = "alloc")]
19use alloc::{format, string::String, vec::Vec};
20use core::{fmt, str};
21
22#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
24pub enum Error {
25 InvalidChar(u8),
27 OddLengthString(usize),
29 InvalidLength(usize, usize),
32}
33
34impl fmt::Display for Error {
35 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
36 match *self {
37 Error::InvalidChar(ch) => write!(f, "invalid hex character {ch}"),
38 Error::OddLengthString(ell) => write!(f, "odd hex string length {ell}"),
39 Error::InvalidLength(ell, ell2) => {
40 write!(f, "bad hex string length {ell2} (expected {ell})")
41 }
42 }
43 }
44}
45
46#[cfg(feature = "std")]
47impl std::error::Error for Error {}
48
49#[cfg(any(test, feature = "std", feature = "alloc"))]
51pub trait ToHex {
52 fn to_hex(&self) -> String;
54}
55
56pub trait FromHex: Sized {
58 fn from_byte_iter<I>(iter: I) -> Result<Self, Error>
60 where I: Iterator<Item = Result<u8, Error>> + ExactSizeIterator + DoubleEndedIterator;
61
62 fn from_hex(s: &str) -> Result<Self, Error> { Self::from_byte_iter(HexIterator::new(s)?) }
64}
65
66#[cfg(any(test, feature = "std", feature = "alloc"))]
67impl<T: fmt::LowerHex> ToHex for T {
68 fn to_hex(&self) -> String { format!("{self:x}") }
70}
71
72pub struct HexIterator<'a> {
74 iter: str::Bytes<'a>,
77}
78
79impl<'a> HexIterator<'a> {
80 pub fn new(s: &'a str) -> Result<HexIterator<'a>, Error> {
83 if s.len() % 2 != 0 {
84 Err(Error::OddLengthString(s.len()))
85 } else {
86 Ok(HexIterator { iter: s.bytes() })
87 }
88 }
89}
90
91fn chars_to_hex(hi: u8, lo: u8) -> Result<u8, Error> {
92 let hih = (hi as char).to_digit(16).ok_or(Error::InvalidChar(hi))?;
93 let loh = (lo as char).to_digit(16).ok_or(Error::InvalidChar(lo))?;
94
95 let ret = (hih << 4) + loh;
96 Ok(ret as u8)
97}
98
99impl<'a> Iterator for HexIterator<'a> {
100 type Item = Result<u8, Error>;
101
102 fn next(&mut self) -> Option<Result<u8, Error>> {
103 let hi = self.iter.next()?;
104 let lo = self.iter.next().unwrap();
105 Some(chars_to_hex(hi, lo))
106 }
107
108 fn size_hint(&self) -> (usize, Option<usize>) {
109 let (min, max) = self.iter.size_hint();
110 (min / 2, max.map(|x| x / 2))
111 }
112}
113
114impl<'a> DoubleEndedIterator for HexIterator<'a> {
115 fn next_back(&mut self) -> Option<Result<u8, Error>> {
116 let lo = self.iter.next_back()?;
117 let hi = self.iter.next_back().unwrap();
118 Some(chars_to_hex(hi, lo))
119 }
120}
121
122impl<'a> ExactSizeIterator for HexIterator<'a> {}
123
124pub fn format_hex(data: &[u8], f: &mut fmt::Formatter) -> fmt::Result {
127 let prec = f.precision().unwrap_or(2 * data.len());
128 let width = f.width().unwrap_or(2 * data.len());
129 for _ in (2 * data.len())..width {
130 f.write_str("0")?;
131 }
132 for ch in data.iter().take(prec / 2) {
133 write!(f, "{:02x}", *ch)?;
134 }
135 if prec < 2 * data.len() && prec % 2 == 1 {
136 write!(f, "{:x}", data[prec / 2] / 16)?;
137 }
138 Ok(())
139}
140
141pub fn format_hex_reverse(data: &[u8], f: &mut fmt::Formatter) -> fmt::Result {
144 let prec = f.precision().unwrap_or(2 * data.len());
145 let width = f.width().unwrap_or(2 * data.len());
146 for _ in (2 * data.len())..width {
147 f.write_str("0")?;
148 }
149 for ch in data.iter().rev().take(prec / 2) {
150 write!(f, "{:02x}", *ch)?;
151 }
152 if prec < 2 * data.len() && prec % 2 == 1 {
153 write!(f, "{:x}", data[data.len() - 1 - prec / 2] / 16)?;
154 }
155 Ok(())
156}
157
158#[cfg(any(test, feature = "std", feature = "alloc"))]
159impl ToHex for [u8] {
160 fn to_hex(&self) -> String {
161 use core::fmt::Write;
162 let mut ret = String::with_capacity(2 * self.len());
163 for ch in self {
164 write!(ret, "{ch:02x}").expect("writing to string");
165 }
166 ret
167 }
168}
169
170#[cfg(any(test, feature = "std", feature = "alloc"))]
171impl FromHex for Vec<u8> {
172 fn from_byte_iter<I>(iter: I) -> Result<Self, Error>
173 where I: Iterator<Item = Result<u8, Error>> + ExactSizeIterator + DoubleEndedIterator {
174 iter.collect()
175 }
176}
177
178macro_rules! impl_fromhex_array {
179 ($len:expr) => {
180 impl FromHex for [u8; $len] {
181 fn from_byte_iter<I>(iter: I) -> Result<Self, Error>
182 where I: Iterator<Item = Result<u8, Error>> + ExactSizeIterator + DoubleEndedIterator
183 {
184 if iter.len() == $len {
185 let mut ret = [0; $len];
186 for (n, byte) in iter.enumerate() {
187 ret[n] = byte?;
188 }
189 Ok(ret)
190 } else {
191 Err(Error::InvalidLength(2 * $len, 2 * iter.len()))
192 }
193 }
194 }
195 };
196}
197
198impl_fromhex_array!(2);
199impl_fromhex_array!(4);
200impl_fromhex_array!(6);
201impl_fromhex_array!(8);
202impl_fromhex_array!(10);
203impl_fromhex_array!(12);
204impl_fromhex_array!(14);
205impl_fromhex_array!(16);
206impl_fromhex_array!(20);
207impl_fromhex_array!(24);
208impl_fromhex_array!(28);
209impl_fromhex_array!(32);
210impl_fromhex_array!(33);
211impl_fromhex_array!(64);
212impl_fromhex_array!(65);
213impl_fromhex_array!(128);
214impl_fromhex_array!(256);
215impl_fromhex_array!(384);
216impl_fromhex_array!(512);
217
218#[cfg(test)]
219mod tests {
220 use core::fmt;
221
222 use super::*;
223
224 #[test]
225 fn hex_roundtrip() {
226 let expected = "0123456789abcdef";
227 let expected_up = "0123456789ABCDEF";
228
229 let parse: Vec<u8> = FromHex::from_hex(expected).expect("parse lowercase string");
230 assert_eq!(parse, vec![0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef]);
231 let ser = parse.to_hex();
232 assert_eq!(ser, expected);
233
234 let parse: Vec<u8> = FromHex::from_hex(expected_up).expect("parse uppercase string");
235 assert_eq!(parse, vec![0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef]);
236 let ser = parse.to_hex();
237 assert_eq!(ser, expected);
238
239 let parse: [u8; 8] = FromHex::from_hex(expected_up).expect("parse uppercase string");
240 assert_eq!(parse, [0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef]);
241 let ser = parse.to_hex();
242 assert_eq!(ser, expected);
243 }
244
245 #[test]
246 fn hex_truncate() {
247 struct HexBytes(Vec<u8>);
248 impl fmt::LowerHex for HexBytes {
249 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { format_hex(&self.0, f) }
250 }
251
252 let bytes = HexBytes(vec![1u8, 2, 3, 4, 5, 6, 7, 8, 9, 10]);
253
254 assert_eq!(format!("{:x}", bytes), "0102030405060708090a");
255
256 for i in 0..20 {
257 assert_eq!(format!("{:.prec$x}", bytes, prec = i), &"0102030405060708090a"[0..i]);
258 }
259
260 assert_eq!(format!("{:25x}", bytes), "000000102030405060708090a");
261 assert_eq!(format!("{:26x}", bytes), "0000000102030405060708090a");
262 }
263
264 #[test]
265 fn hex_truncate_rev() {
266 struct HexBytes(Vec<u8>);
267 impl fmt::LowerHex for HexBytes {
268 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { format_hex_reverse(&self.0, f) }
269 }
270
271 let bytes = HexBytes(vec![1u8, 2, 3, 4, 5, 6, 7, 8, 9, 10]);
272
273 assert_eq!(format!("{:x}", bytes), "0a090807060504030201");
274
275 for i in 0..20 {
276 assert_eq!(format!("{:.prec$x}", bytes, prec = i), &"0a090807060504030201"[0..i]);
277 }
278
279 assert_eq!(format!("{:25x}", bytes), "000000a090807060504030201");
280 assert_eq!(format!("{:26x}", bytes), "0000000a090807060504030201");
281 }
282
283 #[test]
284 fn hex_error() {
285 let oddlen = "0123456789abcdef0";
286 let badchar1 = "Z123456789abcdef";
287 let badchar2 = "012Y456789abcdeb";
288 let badchar3 = "«23456789abcdef";
289
290 assert_eq!(Vec::<u8>::from_hex(oddlen), Err(Error::OddLengthString(17)));
291 assert_eq!(<[u8; 4]>::from_hex(oddlen), Err(Error::OddLengthString(17)));
292 assert_eq!(<[u8; 8]>::from_hex(oddlen), Err(Error::OddLengthString(17)));
293 assert_eq!(Vec::<u8>::from_hex(badchar1), Err(Error::InvalidChar(b'Z')));
294 assert_eq!(Vec::<u8>::from_hex(badchar2), Err(Error::InvalidChar(b'Y')));
295 assert_eq!(Vec::<u8>::from_hex(badchar3), Err(Error::InvalidChar(194)));
296 }
297}