easy_hex/
encode.rs

1use hex::FromHexError;
2
3use crate::{LOWER, UPPER};
4
5/// Encodes a sequence of bytes to a lowercase hex string.
6///
7/// The resulting string is passed to the closure.
8pub fn encode<T, V>(v: &T, out: impl FnOnce(&str) -> V) -> V
9where
10    T: ?Sized + AsRef<[u8]>,
11{
12    fast_serialize::<_, _, LOWER>(v, out)
13}
14
15/// Encodes a sequence of bytes to a uppercase hex string.
16///
17/// The resulting string is passed to the closure.
18pub fn encode_upper<T, V>(v: &T, out: impl FnOnce(&str) -> V) -> V
19where
20    T: ?Sized + AsRef<[u8]>,
21{
22    fast_serialize::<_, _, UPPER>(v, out)
23}
24
25pub(crate) const SMALL_SER_LEN: usize = 128;
26
27pub(crate) fn fast_serialize<T, V, const U: bool>(v: &T, out: impl FnOnce(&str) -> V) -> V
28where
29    T: ?Sized + AsRef<[u8]>,
30{
31    let v = v.as_ref();
32
33    let str_len = v.len() * 2;
34    let mut array;
35    let mut vec;
36    let buf;
37    if str_len <= SMALL_SER_LEN {
38        array = [0; SMALL_SER_LEN];
39        buf = &mut array[..str_len];
40    } else {
41        vec = vec![0; str_len];
42        buf = &mut vec[..];
43    }
44
45    let alpha = if U { HEX_CHARS_UPPER } else { HEX_CHARS_LOWER };
46    // NB: This can never fail, as we ensure the buffer has the rigth size
47    let _ = encode_to_slice(v, buf, alpha);
48
49    // SAFTEY: buffer will only contain ASCII bytes
50    let s: &str = unsafe { std::str::from_utf8_unchecked(buf) };
51    out(s)
52}
53
54// --- code taken from hex crate ----------------
55
56const HEX_CHARS_LOWER: &[u8; 16] = b"0123456789abcdef";
57const HEX_CHARS_UPPER: &[u8; 16] = b"0123456789ABCDEF";
58
59/// taken from hex crate
60fn encode_to_slice<T: AsRef<[u8]>>(
61    input: T,
62    output: &mut [u8],
63    alpha: &[u8; 16],
64) -> Result<(), FromHexError> {
65    if input.as_ref().len() * 2 != output.len() {
66        return Err(FromHexError::InvalidStringLength);
67    }
68
69    for (byte, (i, j)) in input
70        .as_ref()
71        .iter()
72        .zip(generate_iter(input.as_ref().len() * 2))
73    {
74        let (high, low) = byte2hex(*byte, alpha);
75        output[i] = high;
76        output[j] = low;
77    }
78
79    Ok(())
80}
81
82/// taken from hex crate
83/// generates an iterator like this
84/// (0, 1)
85/// (2, 3)
86/// (4, 5)
87/// (6, 7)
88/// ...
89#[inline]
90fn generate_iter(len: usize) -> impl Iterator<Item = (usize, usize)> {
91    (0..len).step_by(2).zip((0..len).skip(1).step_by(2))
92}
93
94/// taken from hex crate
95/// the inverse of `val`.
96#[inline]
97#[must_use]
98fn byte2hex(byte: u8, table: &[u8; 16]) -> (u8, u8) {
99    let high = table[((byte & 0xf0) >> 4) as usize];
100    let low = table[(byte & 0x0f) as usize];
101
102    (high, low)
103}