1#![cfg_attr(not(feature = "std"), no_std)]
14#![warn(missing_docs)]
15
16use core::fmt;
17use core::iter::{self, FromIterator};
18
19pub use self::FromHexError::*;
20
21pub trait ToHex {
23 fn to_hex<T: FromIterator<char>>(&self) -> T;
26}
27
28static CHARS: &'static [u8] = b"0123456789abcdef";
29
30impl ToHex for [u8] {
31 fn to_hex<T: FromIterator<char>>(&self) -> T {
44 ToHexIter::new(self.iter()).collect()
45 }
46}
47
48impl<'a, T: ?Sized + ToHex> ToHex for &'a T {
49 fn to_hex<U: FromIterator<char>>(&self) -> U {
50 (**self).to_hex()
51 }
52}
53
54pub struct ToHexIter<T> {
56 live: Option<char>,
57 inner: T,
58}
59
60impl<T> ToHexIter<T> {
61 pub fn new(inner: T) -> Self {
73 Self {
74 live: None,
75 inner,
76 }
77 }
78}
79
80impl<'a, T: Iterator<Item = &'a u8>> Iterator for ToHexIter<T> {
81 type Item = char;
82
83 fn next(&mut self) -> Option<char> {
84 if let Some(live) = self.live.take() {
85 return Some(live);
86 }
87
88 self.inner.next().map(|&byte| {
89 let current = CHARS[(byte >> 4) as usize] as char;
90 self.live = Some(CHARS[(byte & 0xf) as usize] as char);
91 current
92 })
93 }
94
95 fn size_hint(&self) -> (usize, Option<usize>) {
96 let (a, b) = self.inner.size_hint();
97 (a.saturating_mul(2), b.map(|b| b.saturating_mul(2)))
98 }
99}
100
101impl<'a, T: iter::ExactSizeIterator + Iterator<Item = &'a u8>> iter::ExactSizeIterator for ToHexIter<T> {
102 fn len(&self) -> usize {
103 let mut len = self.inner.len() * 2;
104 if self.live.is_some() {
105 len += 1;
106 }
107 len
108 }
109}
110
111pub trait FromHex {
113 fn from_hex<T: FromIterator<u8>>(&self) -> Result<T, FromHexError>;
116}
117
118#[derive(Clone, Copy)]
120pub enum FromHexError {
121 InvalidHexCharacter(char, usize),
123 InvalidHexLength,
125}
126
127impl fmt::Debug for FromHexError {
128 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
129 match *self {
130 InvalidHexCharacter(ch, idx) =>
131 write!(f, "Invalid character '{}' at position {}", ch, idx),
132 InvalidHexLength => write!(f, "Invalid input length"),
133 }
134 }
135}
136
137#[cfg(feature = "std")]
138impl ::std::error::Error for FromHexError {
139 fn description(&self) -> &str {
140 match *self {
141 InvalidHexCharacter(_, _) => "invalid character",
142 InvalidHexLength => "invalid length",
143 }
144 }
145}
146
147#[cfg(feature = "std")]
148impl fmt::Display for FromHexError {
149 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
150 fmt::Debug::fmt(&self, f)
151 }
152}
153
154#[cfg(not(feature = "std"))]
155impl fmt::Display for FromHexError {
156 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
157 match *self {
158 InvalidHexCharacter(ch, idx) => {
159 f.write_str("invalid character: ")?;
160 ch.fmt(f)?;
161 f.write_str(" at index ")?;
162 idx.fmt(f)
163 }
164 InvalidHexLength => f.write_str("invalid length"),
165 }
166 }
167}
168
169impl FromHex for str {
170 fn from_hex<T: FromIterator<u8>>(&self) -> Result<T, FromHexError> {
194 FromHexIter::new(self).collect()
195 }
196}
197
198impl<'a, T: ?Sized + FromHex> FromHex for &'a T {
199 fn from_hex<U: FromIterator<u8>>(&self) -> Result<U, FromHexError> {
200 (**self).from_hex()
201 }
202}
203
204pub struct FromHexIter<'a> {
206 err: bool,
207 inner: &'a str,
208 iter: iter::Enumerate<core::str::Bytes<'a>>,
209}
210
211impl<'a> FromHexIter<'a> {
212 pub fn new(inner: &'a str) -> Self {
223 let iter = inner.bytes().enumerate();
224 Self {
225 err: false,
226 inner,
227 iter,
228 }
229 }
230}
231
232impl<'a> Iterator for FromHexIter<'a> {
233 type Item = Result<u8, FromHexError>;
234
235 fn next(&mut self) -> Option<Result<u8, FromHexError>> {
236 if self.err {
237 return None;
238 }
239
240 let mut modulus = 0;
241 let mut buf = 0;
242 for (idx, byte) in &mut self.iter {
243 buf <<= 4;
244
245 match byte {
246 b'A'..=b'F' => buf |= byte - b'A' + 10,
247 b'a'..=b'f' => buf |= byte - b'a' + 10,
248 b'0'..=b'9' => buf |= byte - b'0',
249 b' '|b'\r'|b'\n'|b'\t' => {
250 buf >>= 4;
251 continue
252 }
253 _ => {
254 let ch = self.inner[idx..].chars().next().unwrap();
255 self.err = true;
256 return Some(Err(InvalidHexCharacter(ch, idx)));
257 }
258 }
259
260 modulus += 1;
261 if modulus == 2 {
262 return Some(Ok(buf));
263 }
264 }
265
266 if modulus != 0 {
267 self.err = true;
268 return Some(Err(InvalidHexLength));
269 }
270
271 None
272 }
273
274 fn size_hint(&self) -> (usize, Option<usize>) {
275 let (a, b) = self.iter.size_hint();
276 (a / 2, b.map(|b| b / 2))
277 }
278}
279
280#[cfg(test)]
281mod tests {
282 use super::{FromHex, ToHex};
283 #[cfg(not(feature = "std"))]
284 extern crate alloc;
285 #[cfg(not(feature = "std"))]
286 use alloc::{string::String, vec::Vec, format};
287
288 #[test]
289 pub fn test_to_hex() {
290 assert_eq!("foobar".as_bytes().to_hex::<String>(), "666f6f626172");
291 }
292
293 #[test]
294 pub fn test_from_hex_okay() {
295 assert_eq!("666f6f626172".from_hex::<Vec<_>>().unwrap(),
296 b"foobar");
297 assert_eq!("666F6F626172".from_hex::<Vec<_>>().unwrap(),
298 b"foobar");
299 }
300
301 #[test]
302 pub fn test_from_hex_odd_len() {
303 assert!("666".from_hex::<Vec<_>>().is_err());
304 assert!("66 6".from_hex::<Vec<_>>().is_err());
305 }
306
307 #[test]
308 pub fn test_from_hex_invalid_char() {
309 assert!("66y6".from_hex::<Vec<_>>().is_err());
310 }
311
312 #[test]
313 pub fn test_from_hex_ignores_whitespace() {
314 assert_eq!("666f 6f6\r\n26172 ".from_hex::<Vec<_>>().unwrap(),
315 b"foobar");
316 }
317
318 #[test]
319 pub fn test_to_hex_all_bytes() {
320 for i in 0..256 {
321 assert_eq!([i as u8].to_hex::<String>(), format!("{:02x}", i));
322 }
323 }
324
325 #[test]
326 pub fn test_from_hex_all_bytes() {
327 for i in 0..256 {
328 let ii: &[u8] = &[i as u8];
329 assert_eq!(format!("{:02x}", i).from_hex::<Vec<_>>().unwrap(),
330 ii);
331 assert_eq!(format!("{:02X}", i).from_hex::<Vec<_>>().unwrap(),
332 ii);
333 }
334 }
335}