hex_noalloc/
lib.rs

1#![cfg_attr(feature = "benchmarks", feature(test))]
2#![cfg_attr(not(feature = "std"), no_std)]
3
4// Copyright (c) 2013-2014 The Rust Project Developers.
5// Copyright (c) 2015-2018 The rust-hex Developers.
6//
7// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
8// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
9// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
10// option. This file may not be copied, modified, or distributed
11// except according to those terms.
12//! Encoding and decoding hex strings.
13//!
14//! For most cases, you can simply use the `decode()`, `encode()` and
15//! `encode_upper()` functions. If you need a bit more control, use the traits
16//! `ToHex` and `FromHex` instead.
17//!
18//! # Example
19//!
20//! ```
21//! extern crate hex;
22//!
23//! #[cfg(feature = "std")]
24//! fn main() {
25//!     let hex_string = hex::encode("Hello world!");
26//!     println!("{}", hex_string); // Prints '48656c6c6f20776f726c6421'
27//! }
28//!
29//! #[cfg(not(feature = "std"))]
30//! fn main() {
31//! }
32//! ```
33
34#[cfg(feature = "std")]
35extern crate core;
36
37#[cfg(feature = "std")]
38use std::error;
39use core::fmt;
40use core::iter;
41
42/// Encoding values as hex string.
43///
44/// This trait is implemented for all `T` which implement `AsRef<[u8]>`. This
45/// includes `String`, `str`, `Vec<u8>` and `[u8]`.
46///
47/// # Example
48///
49/// ```
50/// use hex::ToHex;
51///
52/// println!("{}", "Hello world!".encode_hex::<String>());
53/// ```
54///
55/// *Note*: instead of using this trait, you might want to use `encode()`.
56pub trait ToHex {
57    /// Encode the hex strict representing `self` into the result.. Lower case
58    /// letters are used (e.g. `f9b4ca`)
59    fn encode_hex<T: iter::FromIterator<char>>(&self) -> T;
60
61    /// Encode the hex strict representing `self` into the result.. Lower case
62    /// letters are used (e.g. `F9B4CA`)
63    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/// The error type for decoding a hex string into `Vec<u8>` or `[u8; N]`.
134#[derive(Debug, Clone, Copy, PartialEq)]
135pub enum FromHexError {
136    /// An invalid character was found. Valid ones are: `0...9`, `a...f`
137    /// or `A...F`.
138    InvalidHexCharacter {
139        c: char,
140        index: usize,
141    },
142
143    /// A hex string's length needs to be even, as two digits correspond to
144    /// one byte.
145    OddLength,
146
147    /// If the hex string is decoded into a fixed sized container, such as an
148    /// array, the hex string's length * 2 has to match the container's
149    /// length.
150    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
178/// Types that can be decoded from a hex string.
179///
180/// This trait is implemented for `Vec<u8>` and small `u8`-arrays.
181///
182/// # Example
183///
184/// ```
185/// use hex::FromHex;
186///
187/// match &<[u8; 12]>::from_hex("48656c6c6f20776f726c6421") {
188///     Ok(vec) => {
189///         for &b in vec {
190///             println!("{}", b as char);
191///         }
192///     }
193///     Err(e) => {
194///         // Deal with the error ...
195///     }
196/// }
197/// ```
198pub trait FromHex: Sized {
199    type Error;
200
201    /// Creates an instance of type `Self` from the given hex string, or fails
202    /// with a custom error type.
203    ///
204    /// Both, upper and lower case characters are valid and can even be
205    /// mixed (e.g. `f9b4ca`, `F9B4CA` and `f9B4Ca` are all valid strings).
206    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
239// Helper macro to implement the trait for a few fixed sized arrays. Once Rust
240// has type level integers, this should be removed.
241macro_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/// Encodes `data` as hex string using lowercase characters.
280///
281/// Lowercase characters are used (e.g. `f9b4ca`). The resulting string's
282/// length is always even, each byte in `data` is always encoded using two hex
283/// digits. Thus, the resulting string contains exactly twice as many bytes as
284/// the input data.
285///
286/// # Example
287///
288/// ```
289/// assert_eq!(hex::encode("Hello world!"), "48656c6c6f20776f726c6421");
290/// assert_eq!(hex::encode(vec![1, 2, 3, 15, 16]), "0102030f10");
291/// ```
292#[cfg(feature = "std")]
293pub fn encode<T: AsRef<[u8]>>(data: T) -> String {
294    data.encode_hex()
295}
296
297/// Encodes `data` as hex string using uppercase characters.
298///
299/// Apart from the characters' casing, this works exactly like `encode()`.
300///
301/// # Example
302///
303/// ```
304/// assert_eq!(hex::encode_upper("Hello world!"), "48656C6C6F20776F726C6421");
305/// assert_eq!(hex::encode_upper(vec![1, 2, 3, 15, 16]), "0102030F10");
306/// ```
307#[cfg(feature = "std")]
308pub fn encode_upper<T: AsRef<[u8]>>(data: T) -> String {
309    data.encode_hex_upper()
310}
311
312/// Decodes a hex string into raw bytes.
313///
314/// Both, upper and lower case characters are valid in the input string and can
315/// even be mixed (e.g. `f9b4ca`, `F9B4CA` and `f9B4Ca` are all valid strings).
316///
317/// # Example
318/// ```
319/// assert_eq!(
320///     hex::decode("48656c6c6f20776f726c6421"),
321///     Ok("Hello world!".to_owned().into_bytes())
322/// );
323///
324/// assert_eq!(hex::decode("123"), Err(hex::FromHexError::OddLength));
325/// assert!(hex::decode("foo").is_err());
326/// ```
327#[cfg(feature = "std")]
328pub fn decode<T: AsRef<[u8]>>(data: T) -> Result<Vec<u8>, FromHexError> {
329    FromHex::from_hex(data)
330}
331
332/// Decode a hex string into a mutable bytes slice.
333///
334/// Both, upper and lower case characters are valid in the input string and can
335/// even be mixed (e.g. `f9b4ca`, `F9B4CA` and `f9B4Ca` are all valid strings).
336///
337/// # Example
338/// ```
339/// let mut bytes = [0u8; 4];
340/// assert_eq!(hex::decode_to_slice("6b697769", &mut bytes as &mut [u8]), Ok(()));
341/// assert_eq!(&bytes, b"kiwi");
342/// ```
343pub 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}