1#![cfg_attr(feature = "benchmarks", feature(test))]
2#![cfg_attr(not(feature = "std"), no_std)]
3
4#[cfg(feature = "std")]
35extern crate core;
36
37#[cfg(feature = "std")]
38use std::error;
39use core::fmt;
40use core::iter;
41
42pub trait ToHex {
57 fn encode_hex<T: iter::FromIterator<char>>(&self) -> T;
60
61 fn encode_hex_upper<T: iter::FromIterator<char>>(&self) -> T;
64}
65
66const HEX_CHARS_LOWER: &'static[u8; 16] = b"0123456789abcdef";
67const HEX_CHARS_UPPER: &'static[u8; 16] = b"0123456789ABCDEF";
68
69struct BytesToHexChars<'a> {
70 inner: ::core::slice::Iter<'a, u8>,
71 table: &'static [u8; 16],
72 next: Option<char>,
73}
74
75impl<'a> BytesToHexChars<'a> {
76 fn new(inner: &'a [u8], table: &'static [u8; 16]) -> BytesToHexChars<'a> {
77 BytesToHexChars {
78 inner: inner.iter(),
79 table: table,
80 next: None,
81 }
82 }
83}
84
85impl<'a> Iterator for BytesToHexChars<'a> {
86 type Item = char;
87
88 fn next(&mut self) -> Option<Self::Item> {
89 match self.next.take() {
90 Some(current) => Some(current),
91 None => {
92 self.inner.next().map(|byte| {
93 let current = self.table[(byte >> 4) as usize] as char;
94 self.next = Some(self.table[(byte & 0xf) as usize] as char);
95 current
96 })
97 }
98 }
99 }
100
101 fn size_hint(&self) -> (usize, Option<usize>) {
102 let length = self.len();
103 (length, Some(length))
104 }
105}
106
107impl<'a> iter::ExactSizeIterator for BytesToHexChars<'a> {
108 fn len(&self) -> usize {
109 let mut length = self.inner.len() * 2;
110 if self.next.is_some() {
111 length += 1;
112 }
113 length
114 }
115}
116
117fn encode_to_iter<T: iter::FromIterator<char>>(table: &'static [u8; 16],
118 source: &[u8]) -> T
119{
120 BytesToHexChars::new(source, table).collect()
121}
122
123impl<T: AsRef<[u8]>> ToHex for T {
124 fn encode_hex<U: iter::FromIterator<char>>(&self) -> U {
125 encode_to_iter(HEX_CHARS_LOWER, self.as_ref())
126 }
127
128 fn encode_hex_upper<U: iter::FromIterator<char>>(&self) -> U {
129 encode_to_iter(HEX_CHARS_UPPER, self.as_ref())
130 }
131}
132
133#[derive(Debug, Clone, Copy, PartialEq)]
135pub enum FromHexError {
136 InvalidHexCharacter {
139 c: char,
140 index: usize,
141 },
142
143 OddLength,
146
147 InvalidStringLength,
151}
152
153#[cfg(feature = "std")]
154impl error::Error for FromHexError {
155 fn description(&self) -> &str {
156 match *self {
157 FromHexError::InvalidHexCharacter { .. } => "invalid character",
158 FromHexError::OddLength => "odd number of digits",
159 FromHexError::InvalidStringLength => "invalid string length",
160
161 }
162 }
163}
164
165impl fmt::Display for FromHexError {
166 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
167 match *self {
168 FromHexError::InvalidHexCharacter { c, index } =>
169 write!(f, "Invalid character '{}' at position {}", c, index),
170 FromHexError::OddLength =>
171 write!(f, "Odd number of digits"),
172 FromHexError::InvalidStringLength =>
173 write!(f, "Invalid string length"),
174 }
175 }
176}
177
178pub trait FromHex: Sized {
199 type Error;
200
201 fn from_hex<T: AsRef<[u8]>>(hex: T) -> Result<Self, Self::Error>;
207}
208
209fn val(c: u8, idx: usize) -> Result<u8, FromHexError> {
210 match c {
211 b'A'...b'F' => Ok(c - b'A' + 10),
212 b'a'...b'f' => Ok(c - b'a' + 10),
213 b'0'...b'9' => Ok(c - b'0'),
214 _ => {
215 Err(FromHexError::InvalidHexCharacter {
216 c: c as char,
217 index: idx,
218 })
219 }
220 }
221}
222
223#[cfg(feature = "std")]
224impl FromHex for Vec<u8> {
225 type Error = FromHexError;
226
227 fn from_hex<T: AsRef<[u8]>>(hex: T) -> Result<Self, Self::Error> {
228 let hex = hex.as_ref();
229 if hex.len() % 2 != 0 {
230 return Err(FromHexError::OddLength);
231 }
232
233 hex.chunks(2).enumerate().map(|(i, pair)| {
234 Ok(val(pair[0], 2 * i)? << 4 | val(pair[1], 2 * i + 1)?)
235 }).collect()
236 }
237}
238
239macro_rules! from_hex_array_impl {
242 ($($len:expr)+) => {$(
243 impl FromHex for [u8; $len] {
244 type Error = FromHexError;
245
246 fn from_hex<T: AsRef<[u8]>>(hex: T) -> Result<Self, Self::Error> {
247 let mut out = [0u8; $len];
248 decode_to_slice(hex, &mut out as &mut [u8])?;
249 Ok(out)
250 }
251 }
252 )+}
253}
254
255from_hex_array_impl! {
256 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
257 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32
258 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48
259 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64
260 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80
261 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96
262 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112
263 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128
264 160 192 200 224 256 384 512 768 1024 2048 4096 8192 16384 32768
265}
266
267#[cfg(any(target_pointer_width = "32", target_pointer_width = "64"))]
268from_hex_array_impl! {
269 65536 131072 262144 524288 1048576 2097152 4194304 8388608
270 16777216 33554432 67108864 134217728 268435456 536870912
271 1073741824 2147483648
272}
273
274#[cfg(target_pointer_width = "64")]
275from_hex_array_impl! {
276 4294967296
277}
278
279#[cfg(feature = "std")]
293pub fn encode<T: AsRef<[u8]>>(data: T) -> String {
294 data.encode_hex()
295}
296
297#[cfg(feature = "std")]
308pub fn encode_upper<T: AsRef<[u8]>>(data: T) -> String {
309 data.encode_hex_upper()
310}
311
312#[cfg(feature = "std")]
328pub fn decode<T: AsRef<[u8]>>(data: T) -> Result<Vec<u8>, FromHexError> {
329 FromHex::from_hex(data)
330}
331
332pub fn decode_to_slice<T: AsRef<[u8]>>(data: T, out: &mut [u8]) -> Result<(), FromHexError> {
344 let data = data.as_ref();
345
346 if data.len() % 2 != 0 {
347 return Err(FromHexError::OddLength);
348 }
349 if data.len() / 2 != out.len() {
350 return Err(FromHexError::InvalidStringLength);
351 }
352
353 for (i, byte) in out.iter_mut().enumerate() {
354 *byte = val(data[2 * i], 2 * i)? << 4
355 | val(data[2 * i + 1], 2 * i + 1)?;
356 }
357
358 Ok(())
359}
360
361#[cfg(test)]
362mod test {
363 use super::{FromHex, FromHexError};
364
365 #[test]
366 #[cfg(feature = "std")]
367 fn test_encode() {
368 use super::encode;
369
370 assert_eq!(encode("foobar"), "666f6f626172");
371 }
372
373 #[test]
374 #[cfg(feature = "std")]
375 fn test_decode() {
376 use super::decode;
377
378 assert_eq!(decode("666f6f626172"), Ok("foobar".to_owned().into_bytes()));
379 }
380
381 #[test]
382 pub fn test_from_hex_okay_str() {
383 assert_eq!(
384 <[u8; 6]>::from_hex("666f6f626172"),
385 Ok(*b"foobar")
386 );
387 assert_eq!(
388 <[u8; 6]>::from_hex("666F6F626172"),
389 Ok(*b"foobar")
390 );
391 }
392
393 #[test]
394 pub fn test_from_hex_okay_bytes() {
395 assert_eq!(
396 <[u8; 6]>::from_hex(b"666f6f626172"),
397 Ok(*b"foobar")
398 );
399 assert_eq!(
400 <[u8; 6]>::from_hex(b"666F6F626172"),
401 Ok(*b"foobar")
402 );
403 }
404
405 #[test]
406 pub fn test_invalid_length() {
407 assert_eq!(
408 <[u8; 1]>::from_hex("1"),
409 Err(FromHexError::OddLength)
410 );
411 assert_eq!(
412 <[u8; 1]>::from_hex("666f6f6261721"),
413 Err(FromHexError::OddLength)
414 );
415 }
416
417 #[test]
418 pub fn test_invalid_char() {
419 assert_eq!(
420 <[u8; 2]>::from_hex("66ag"),
421 Err(FromHexError::InvalidHexCharacter {
422 c: 'g',
423 index: 3
424 })
425 );
426 }
427
428 #[test]
429 pub fn test_empty() {
430 assert_eq!(
431 <[u8; 0]>::from_hex(""),
432 Ok(*b"")
433 );
434 }
435
436 #[test]
437 pub fn test_from_hex_whitespace() {
438 assert_eq!(
439 <[u8; 6]>::from_hex("666f 6f62617"),
440 Err(FromHexError::InvalidHexCharacter {
441 c: ' ',
442 index: 4
443 })
444 );
445 }
446}
447
448
449#[cfg(all(feature = "benchmarks", test))]
450mod bench {
451 extern crate test;
452 use self::test::Bencher;
453
454 use super::*;
455
456 const MY_OWN_SOURCE: &[u8] = include_bytes!("lib.rs");
457
458 #[bench]
459 fn a_bench(b: &mut Bencher) {
460 b.bytes = MY_OWN_SOURCE.len() as u64;
461
462 b.iter(|| {
463 encode(MY_OWN_SOURCE)
464 });
465 }
466}