1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
use crate::Error::{InsufficientTargetSpace, IntegerOverflow};
use crate::{encode_string_unchecked, Encoder, Error, StringEncoder};

/// Responsible for hex encoding data.
#[derive(Copy, Clone, Ord, PartialOrd, Eq, PartialEq, Hash, Debug)]
pub struct HexEncoder {
    encoding: &'static [u8; 16],
}

impl HexEncoder {
    //! Encoders

    /// The lowercase hex encoder.
    pub const LOWER: Self = Self {
        encoding: b"0123456789abcdef",
    };

    /// The uppercase hex encoder.
    pub const UPPER: Self = Self {
        encoding: b"0123456789ABCDEF",
    };
}

impl HexEncoder {
    //! Encoding

    /// Encodes the byte as two hex chars.
    #[inline(always)]
    pub const fn encode(&self, b: u8) -> (u8, u8) {
        (
            self.encoding[b as usize >> 4],
            self.encoding[b as usize & 0xF],
        )
    }
}

impl Encoder for HexEncoder {
    fn encoded_len(&self, data: &[u8]) -> Result<usize, Error> {
        data.len().checked_mul(2).ok_or(IntegerOverflow)
    }

    fn encode_slice(&self, data: &[u8], target: &mut [u8]) -> Result<usize, Error> {
        let encoded_len: usize = self.encoded_len(data)?;
        if target.len() < encoded_len {
            Err(InsufficientTargetSpace)
        } else {
            let target: &mut [u8] = &mut target[..encoded_len];
            for (d, t) in data.iter().zip(target.chunks_exact_mut(2)) {
                let (high, low) = self.encode(*d);
                t[0] = high;
                t[1] = low;
            }
            Ok(encoded_len)
        }
    }
}

impl StringEncoder for HexEncoder {
    fn encode_string(&self, data: &[u8], target: &mut String) -> Result<usize, Error> {
        unsafe { encode_string_unchecked(self, data, target) }
    }
}