Coverage Report

Created: 2025-07-23 07:29

/rust/registry/src/index.crates.io-6f17d22bba15001f/hex-0.4.3/src/lib.rs
Line
Count
Source (jump to first uncovered line)
1
// Copyright (c) 2013-2014 The Rust Project Developers.
2
// Copyright (c) 2015-2020 The rust-hex Developers.
3
//
4
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
5
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
6
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
7
// option. This file may not be copied, modified, or distributed
8
// except according to those terms.
9
//! Encoding and decoding hex strings.
10
//!
11
//! For most cases, you can simply use the [`decode`], [`encode`] and
12
//! [`encode_upper`] functions. If you need a bit more control, use the traits
13
//! [`ToHex`] and [`FromHex`] instead.
14
//!
15
//! # Example
16
//!
17
//! ```
18
//! # #[cfg(not(feature = "alloc"))]
19
//! # let mut output = [0; 0x18];
20
//! #
21
//! # #[cfg(not(feature = "alloc"))]
22
//! # hex::encode_to_slice(b"Hello world!", &mut output).unwrap();
23
//! #
24
//! # #[cfg(not(feature = "alloc"))]
25
//! # let hex_string = ::core::str::from_utf8(&output).unwrap();
26
//! #
27
//! # #[cfg(feature = "alloc")]
28
//! let hex_string = hex::encode("Hello world!");
29
//!
30
//! println!("{}", hex_string); // Prints "48656c6c6f20776f726c6421"
31
//!
32
//! # assert_eq!(hex_string, "48656c6c6f20776f726c6421");
33
//! ```
34
35
#![doc(html_root_url = "https://docs.rs/hex/0.4.3")]
36
#![cfg_attr(not(feature = "std"), no_std)]
37
#![cfg_attr(docsrs, feature(doc_cfg))]
38
#![allow(clippy::unreadable_literal)]
39
40
#[cfg(feature = "alloc")]
41
extern crate alloc;
42
#[cfg(feature = "alloc")]
43
use alloc::{string::String, vec::Vec};
44
45
use core::iter;
46
47
mod error;
48
pub use crate::error::FromHexError;
49
50
#[cfg(feature = "serde")]
51
#[cfg_attr(docsrs, doc(cfg(feature = "serde")))]
52
pub mod serde;
53
#[cfg(feature = "serde")]
54
pub use crate::serde::deserialize;
55
#[cfg(all(feature = "alloc", feature = "serde"))]
56
pub use crate::serde::{serialize, serialize_upper};
57
58
/// Encoding values as hex string.
59
///
60
/// This trait is implemented for all `T` which implement `AsRef<[u8]>`. This
61
/// includes `String`, `str`, `Vec<u8>` and `[u8]`.
62
///
63
/// # Example
64
///
65
/// ```
66
/// use hex::ToHex;
67
///
68
/// println!("{}", "Hello world!".encode_hex::<String>());
69
/// # assert_eq!("Hello world!".encode_hex::<String>(), "48656c6c6f20776f726c6421".to_string());
70
/// ```
71
///
72
/// *Note*: instead of using this trait, you might want to use [`encode()`].
73
pub trait ToHex {
74
    /// Encode the hex strict representing `self` into the result. Lower case
75
    /// letters are used (e.g. `f9b4ca`)
76
    fn encode_hex<T: iter::FromIterator<char>>(&self) -> T;
77
78
    /// Encode the hex strict representing `self` into the result. Upper case
79
    /// letters are used (e.g. `F9B4CA`)
80
    fn encode_hex_upper<T: iter::FromIterator<char>>(&self) -> T;
81
}
82
83
const HEX_CHARS_LOWER: &[u8; 16] = b"0123456789abcdef";
84
const HEX_CHARS_UPPER: &[u8; 16] = b"0123456789ABCDEF";
85
86
struct BytesToHexChars<'a> {
87
    inner: ::core::slice::Iter<'a, u8>,
88
    table: &'static [u8; 16],
89
    next: Option<char>,
90
}
91
92
impl<'a> BytesToHexChars<'a> {
93
    fn new(inner: &'a [u8], table: &'static [u8; 16]) -> BytesToHexChars<'a> {
94
        BytesToHexChars {
95
            inner: inner.iter(),
96
            table,
97
            next: None,
98
        }
99
    }
100
}
101
102
impl<'a> Iterator for BytesToHexChars<'a> {
103
    type Item = char;
104
105
    fn next(&mut self) -> Option<Self::Item> {
106
        match self.next.take() {
107
            Some(current) => Some(current),
108
            None => self.inner.next().map(|byte| {
109
                let current = self.table[(byte >> 4) as usize] as char;
110
                self.next = Some(self.table[(byte & 0x0F) as usize] as char);
111
                current
112
            }),
113
        }
114
    }
115
116
    fn size_hint(&self) -> (usize, Option<usize>) {
117
        let length = self.len();
118
        (length, Some(length))
119
    }
120
}
121
122
impl<'a> iter::ExactSizeIterator for BytesToHexChars<'a> {
123
    fn len(&self) -> usize {
124
        let mut length = self.inner.len() * 2;
125
        if self.next.is_some() {
126
            length += 1;
127
        }
128
        length
129
    }
130
}
131
132
#[inline]
133
fn encode_to_iter<T: iter::FromIterator<char>>(table: &'static [u8; 16], source: &[u8]) -> T {
134
    BytesToHexChars::new(source, table).collect()
135
}
136
137
impl<T: AsRef<[u8]>> ToHex for T {
138
    fn encode_hex<U: iter::FromIterator<char>>(&self) -> U {
139
        encode_to_iter(HEX_CHARS_LOWER, self.as_ref())
140
    }
141
142
    fn encode_hex_upper<U: iter::FromIterator<char>>(&self) -> U {
143
        encode_to_iter(HEX_CHARS_UPPER, self.as_ref())
144
    }
145
}
146
147
/// Types that can be decoded from a hex string.
148
///
149
/// This trait is implemented for `Vec<u8>` and small `u8`-arrays.
150
///
151
/// # Example
152
///
153
/// ```
154
/// use core::str;
155
/// use hex::FromHex;
156
///
157
/// let buffer = <[u8; 12]>::from_hex("48656c6c6f20776f726c6421")?;
158
/// let string = str::from_utf8(&buffer).expect("invalid buffer length");
159
///
160
/// println!("{}", string); // prints "Hello world!"
161
/// # assert_eq!("Hello world!", string);
162
/// # Ok::<(), hex::FromHexError>(())
163
/// ```
164
pub trait FromHex: Sized {
165
    type Error;
166
167
    /// Creates an instance of type `Self` from the given hex string, or fails
168
    /// with a custom error type.
169
    ///
170
    /// Both, upper and lower case characters are valid and can even be
171
    /// mixed (e.g. `f9b4ca`, `F9B4CA` and `f9B4Ca` are all valid strings).
172
    fn from_hex<T: AsRef<[u8]>>(hex: T) -> Result<Self, Self::Error>;
173
}
174
175
4.16k
fn val(c: u8, idx: usize) -> Result<u8, FromHexError> {
176
4.16k
    match c {
177
3.01k
        b'A'..=b'F' => Ok(c - b'A' + 10),
178
2.28k
        b'a'..=b'f' => Ok(c - b'a' + 10),
179
1.32k
        b'0'..=b'9' => Ok(c - b'0'),
180
202
        _ => Err(FromHexError::InvalidHexCharacter {
181
202
            c: c as char,
182
202
            index: idx,
183
202
        }),
184
    }
185
4.16k
}
186
187
#[cfg(feature = "alloc")]
188
impl FromHex for Vec<u8> {
189
    type Error = FromHexError;
190
191
499
    fn from_hex<T: AsRef<[u8]>>(hex: T) -> Result<Self, Self::Error> {
192
499
        let hex = hex.as_ref();
193
499
        if hex.len() % 2 != 0 {
194
0
            return Err(FromHexError::OddLength);
195
499
        }
196
499
197
499
        hex.chunks(2)
198
499
            .enumerate()
199
2.17k
            .map(|(i, pair)| Ok(val(pair[0], 2 * i)? << 4 | val(pair[1], 2 * i + 1)?))
200
499
            .collect()
201
499
    }
202
}
203
204
// Helper macro to implement the trait for a few fixed sized arrays. Once Rust
205
// has type level integers, this should be removed.
206
macro_rules! from_hex_array_impl {
207
    ($($len:expr)+) => {$(
208
        impl FromHex for [u8; $len] {
209
            type Error = FromHexError;
210
211
            fn from_hex<T: AsRef<[u8]>>(hex: T) -> Result<Self, Self::Error> {
212
                let mut out = [0_u8; $len];
213
                decode_to_slice(hex, &mut out as &mut [u8])?;
214
                Ok(out)
215
            }
216
        }
217
    )+}
218
}
219
220
from_hex_array_impl! {
221
    1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
222
    17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32
223
    33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48
224
    49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64
225
    65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80
226
    81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96
227
    97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112
228
    113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128
229
    160 192 200 224 256 384 512 768 1024 2048 4096 8192 16384 32768
230
}
231
232
#[cfg(any(target_pointer_width = "32", target_pointer_width = "64"))]
233
from_hex_array_impl! {
234
    65536 131072 262144 524288 1048576 2097152 4194304 8388608
235
    16777216 33554432 67108864 134217728 268435456 536870912
236
    1073741824 2147483648
237
}
238
239
#[cfg(target_pointer_width = "64")]
240
from_hex_array_impl! {
241
    4294967296
242
}
243
244
/// Encodes `data` as hex string using lowercase characters.
245
///
246
/// Lowercase characters are used (e.g. `f9b4ca`). The resulting string's
247
/// length is always even, each byte in `data` is always encoded using two hex
248
/// digits. Thus, the resulting string contains exactly twice as many bytes as
249
/// the input data.
250
///
251
/// # Example
252
///
253
/// ```
254
/// assert_eq!(hex::encode("Hello world!"), "48656c6c6f20776f726c6421");
255
/// assert_eq!(hex::encode(vec![1, 2, 3, 15, 16]), "0102030f10");
256
/// ```
257
#[must_use]
258
#[cfg(feature = "alloc")]
259
pub fn encode<T: AsRef<[u8]>>(data: T) -> String {
260
    data.encode_hex()
261
}
262
263
/// Encodes `data` as hex string using uppercase characters.
264
///
265
/// Apart from the characters' casing, this works exactly like `encode()`.
266
///
267
/// # Example
268
///
269
/// ```
270
/// assert_eq!(hex::encode_upper("Hello world!"), "48656C6C6F20776F726C6421");
271
/// assert_eq!(hex::encode_upper(vec![1, 2, 3, 15, 16]), "0102030F10");
272
/// ```
273
#[must_use]
274
#[cfg(feature = "alloc")]
275
pub fn encode_upper<T: AsRef<[u8]>>(data: T) -> String {
276
    data.encode_hex_upper()
277
}
278
279
/// Decodes a hex string into raw bytes.
280
///
281
/// Both, upper and lower case characters are valid in the input string and can
282
/// even be mixed (e.g. `f9b4ca`, `F9B4CA` and `f9B4Ca` are all valid strings).
283
///
284
/// # Example
285
///
286
/// ```
287
/// assert_eq!(
288
///     hex::decode("48656c6c6f20776f726c6421"),
289
///     Ok("Hello world!".to_owned().into_bytes())
290
/// );
291
///
292
/// assert_eq!(hex::decode("123"), Err(hex::FromHexError::OddLength));
293
/// assert!(hex::decode("foo").is_err());
294
/// ```
295
#[cfg(feature = "alloc")]
296
499
pub fn decode<T: AsRef<[u8]>>(data: T) -> Result<Vec<u8>, FromHexError> {
297
499
    FromHex::from_hex(data)
298
499
}
299
300
/// Decode a hex string into a mutable bytes slice.
301
///
302
/// Both, upper and lower case characters are valid in the input string and can
303
/// even be mixed (e.g. `f9b4ca`, `F9B4CA` and `f9B4Ca` are all valid strings).
304
///
305
/// # Example
306
///
307
/// ```
308
/// let mut bytes = [0u8; 4];
309
/// assert_eq!(hex::decode_to_slice("6b697769", &mut bytes as &mut [u8]), Ok(()));
310
/// assert_eq!(&bytes, b"kiwi");
311
/// ```
312
pub fn decode_to_slice<T: AsRef<[u8]>>(data: T, out: &mut [u8]) -> Result<(), FromHexError> {
313
    let data = data.as_ref();
314
315
    if data.len() % 2 != 0 {
316
        return Err(FromHexError::OddLength);
317
    }
318
    if data.len() / 2 != out.len() {
319
        return Err(FromHexError::InvalidStringLength);
320
    }
321
322
    for (i, byte) in out.iter_mut().enumerate() {
323
        *byte = val(data[2 * i], 2 * i)? << 4 | val(data[2 * i + 1], 2 * i + 1)?;
324
    }
325
326
    Ok(())
327
}
328
329
// generates an iterator like this
330
// (0, 1)
331
// (2, 3)
332
// (4, 5)
333
// (6, 7)
334
// ...
335
#[inline]
336
fn generate_iter(len: usize) -> impl Iterator<Item = (usize, usize)> {
337
    (0..len).step_by(2).zip((0..len).skip(1).step_by(2))
338
}
339
340
// the inverse of `val`.
341
#[inline]
342
#[must_use]
343
fn byte2hex(byte: u8, table: &[u8; 16]) -> (u8, u8) {
344
    let high = table[((byte & 0xf0) >> 4) as usize];
345
    let low = table[(byte & 0x0f) as usize];
346
347
    (high, low)
348
}
349
350
/// Encodes some bytes into a mutable slice of bytes.
351
///
352
/// The output buffer, has to be able to hold at least `input.len() * 2` bytes,
353
/// otherwise this function will return an error.
354
///
355
/// # Example
356
///
357
/// ```
358
/// # use hex::FromHexError;
359
/// # fn main() -> Result<(), FromHexError> {
360
/// let mut bytes = [0u8; 4 * 2];
361
///
362
/// hex::encode_to_slice(b"kiwi", &mut bytes)?;
363
/// assert_eq!(&bytes, b"6b697769");
364
/// # Ok(())
365
/// # }
366
/// ```
367
pub fn encode_to_slice<T: AsRef<[u8]>>(input: T, output: &mut [u8]) -> Result<(), FromHexError> {
368
    if input.as_ref().len() * 2 != output.len() {
369
        return Err(FromHexError::InvalidStringLength);
370
    }
371
372
    for (byte, (i, j)) in input
373
        .as_ref()
374
        .iter()
375
        .zip(generate_iter(input.as_ref().len() * 2))
376
    {
377
        let (high, low) = byte2hex(*byte, HEX_CHARS_LOWER);
378
        output[i] = high;
379
        output[j] = low;
380
    }
381
382
    Ok(())
383
}
384
385
#[cfg(test)]
386
mod test {
387
    use super::*;
388
    #[cfg(feature = "alloc")]
389
    use alloc::string::ToString;
390
    use pretty_assertions::assert_eq;
391
392
    #[test]
393
    #[cfg(feature = "alloc")]
394
    fn test_gen_iter() {
395
        let result = vec![(0, 1), (2, 3)];
396
397
        assert_eq!(generate_iter(5).collect::<Vec<_>>(), result);
398
    }
399
400
    #[test]
401
    fn test_encode_to_slice() {
402
        let mut output_1 = [0; 4 * 2];
403
        encode_to_slice(b"kiwi", &mut output_1).unwrap();
404
        assert_eq!(&output_1, b"6b697769");
405
406
        let mut output_2 = [0; 5 * 2];
407
        encode_to_slice(b"kiwis", &mut output_2).unwrap();
408
        assert_eq!(&output_2, b"6b69776973");
409
410
        let mut output_3 = [0; 100];
411
412
        assert_eq!(
413
            encode_to_slice(b"kiwis", &mut output_3),
414
            Err(FromHexError::InvalidStringLength)
415
        );
416
    }
417
418
    #[test]
419
    fn test_decode_to_slice() {
420
        let mut output_1 = [0; 4];
421
        decode_to_slice(b"6b697769", &mut output_1).unwrap();
422
        assert_eq!(&output_1, b"kiwi");
423
424
        let mut output_2 = [0; 5];
425
        decode_to_slice(b"6b69776973", &mut output_2).unwrap();
426
        assert_eq!(&output_2, b"kiwis");
427
428
        let mut output_3 = [0; 4];
429
430
        assert_eq!(
431
            decode_to_slice(b"6", &mut output_3),
432
            Err(FromHexError::OddLength)
433
        );
434
    }
435
436
    #[test]
437
    #[cfg(feature = "alloc")]
438
    fn test_encode() {
439
        assert_eq!(encode("foobar"), "666f6f626172");
440
    }
441
442
    #[test]
443
    #[cfg(feature = "alloc")]
444
    fn test_decode() {
445
        assert_eq!(
446
            decode("666f6f626172"),
447
            Ok(String::from("foobar").into_bytes())
448
        );
449
    }
450
451
    #[test]
452
    #[cfg(feature = "alloc")]
453
    pub fn test_from_hex_okay_str() {
454
        assert_eq!(Vec::from_hex("666f6f626172").unwrap(), b"foobar");
455
        assert_eq!(Vec::from_hex("666F6F626172").unwrap(), b"foobar");
456
    }
457
458
    #[test]
459
    #[cfg(feature = "alloc")]
460
    pub fn test_from_hex_okay_bytes() {
461
        assert_eq!(Vec::from_hex(b"666f6f626172").unwrap(), b"foobar");
462
        assert_eq!(Vec::from_hex(b"666F6F626172").unwrap(), b"foobar");
463
    }
464
465
    #[test]
466
    #[cfg(feature = "alloc")]
467
    pub fn test_invalid_length() {
468
        assert_eq!(Vec::from_hex("1").unwrap_err(), FromHexError::OddLength);
469
        assert_eq!(
470
            Vec::from_hex("666f6f6261721").unwrap_err(),
471
            FromHexError::OddLength
472
        );
473
    }
474
475
    #[test]
476
    #[cfg(feature = "alloc")]
477
    pub fn test_invalid_char() {
478
        assert_eq!(
479
            Vec::from_hex("66ag").unwrap_err(),
480
            FromHexError::InvalidHexCharacter { c: 'g', index: 3 }
481
        );
482
    }
483
484
    #[test]
485
    #[cfg(feature = "alloc")]
486
    pub fn test_empty() {
487
        assert_eq!(Vec::from_hex("").unwrap(), b"");
488
    }
489
490
    #[test]
491
    #[cfg(feature = "alloc")]
492
    pub fn test_from_hex_whitespace() {
493
        assert_eq!(
494
            Vec::from_hex("666f 6f62617").unwrap_err(),
495
            FromHexError::InvalidHexCharacter { c: ' ', index: 4 }
496
        );
497
    }
498
499
    #[test]
500
    pub fn test_from_hex_array() {
501
        assert_eq!(
502
            <[u8; 6] as FromHex>::from_hex("666f6f626172"),
503
            Ok([0x66, 0x6f, 0x6f, 0x62, 0x61, 0x72])
504
        );
505
506
        assert_eq!(
507
            <[u8; 5] as FromHex>::from_hex("666f6f626172"),
508
            Err(FromHexError::InvalidStringLength)
509
        );
510
    }
511
512
    #[test]
513
    #[cfg(feature = "alloc")]
514
    fn test_to_hex() {
515
        assert_eq!(
516
            [0x66, 0x6f, 0x6f, 0x62, 0x61, 0x72].encode_hex::<String>(),
517
            "666f6f626172".to_string(),
518
        );
519
520
        assert_eq!(
521
            [0x66, 0x6f, 0x6f, 0x62, 0x61, 0x72].encode_hex_upper::<String>(),
522
            "666F6F626172".to_string(),
523
        );
524
    }
525
}