macro_toolset/string/
hex.rs

1//! Number to Hex string
2//!
3//! Actually just with [`NumStr`](crate::string::NumStr) you can do so.
4//! However for fixed length hex string, [`const_hex`] does better.
5
6use super::{StringExtT, StringT};
7
8#[derive(Debug, Clone)]
9/// Hex string with fixed length.
10///
11/// # Generic
12///
13/// - N: Length of target buffer, the length of the final string is 2*N (+1 if
14///   with prefix).
15/// - P: Prefix `0x`, default false
16/// - U: Uppercase, default false
17///
18/// For hex string with non-fixed length, use [`NumStr`](super::NumStr).
19pub enum HexStr<'s, const N: usize, const P: bool = false, const U: bool = false> {
20    /// Owned
21    Owned(Vec<u8>),
22
23    /// Borrowed
24    Borrowed(&'s [u8]),
25}
26
27impl<'s, const N: usize, const P: bool, const U: bool> HexStr<'s, N, P, U> {
28    #[inline]
29    /// Create a new hex string from give slice.
30    pub const fn new(value: &'s [u8]) -> Self {
31        Self::Borrowed(value)
32    }
33
34    #[inline]
35    /// Create a new hex string from given owned slice.
36    pub const fn new_owned(value: Vec<u8>) -> Self {
37        Self::Owned(value)
38    }
39
40    #[inline]
41    /// Set with prefix `0x`
42    pub fn set_with_prefix<const NP: bool>(self) -> HexStr<'s, N, NP, U> {
43        match self {
44            Self::Borrowed(value) => HexStr::Borrowed(value),
45            Self::Owned(value) => HexStr::Owned(value),
46        }
47    }
48
49    #[inline]
50    /// Set to uppercase
51    pub fn set_uppercase<const NU: bool>(self) -> HexStr<'s, N, P, NU> {
52        match self {
53            Self::Borrowed(value) => HexStr::Borrowed(value),
54            Self::Owned(value) => HexStr::Owned(value),
55        }
56    }
57
58    #[inline]
59    /// Encode to string
60    fn encode<T>(&self, string: &mut T)
61    where
62        T: for<'a> Extend<&'a u8>,
63    {
64        let mut buffer = [0; N];
65
66        for (idx, &i) in (0..N).rev().zip(
67            match self {
68                Self::Borrowed(value) => value,
69                Self::Owned(value) => value.as_slice(),
70            }
71            .iter()
72            .rev(),
73        ) {
74            buffer[idx] = i
75        }
76
77        if U {
78            string.extend(
79                const_hex::Buffer::<N, P>::new()
80                    .const_format_upper(&buffer)
81                    .as_bytes(),
82            );
83        } else {
84            string.extend(
85                const_hex::Buffer::<N, P>::new()
86                    .const_format(&buffer)
87                    .as_bytes(),
88            );
89        }
90    }
91}
92
93impl<const N: usize, const P: bool, const U: bool> StringT for HexStr<'_, N, P, U> {
94    #[inline]
95    fn encode_to_buf(self, string: &mut Vec<u8>) {
96        self.encode(string);
97    }
98
99    #[inline]
100    fn encode_to_buf_with_separator(self, string: &mut Vec<u8>, separator: &str) {
101        self.encode(string);
102        string.extend(separator.as_bytes());
103    }
104
105    #[inline]
106    fn encode_to_bytes_buf(self, string: &mut bytes::BytesMut) {
107        self.encode(string);
108    }
109
110    #[inline]
111    fn encode_to_bytes_buf_with_separator(self, string: &mut bytes::BytesMut, separator: &str) {
112        self.encode(string);
113        string.extend(separator.as_bytes());
114    }
115}
116
117impl<const N: usize, const P: bool, const U: bool> StringExtT for HexStr<'_, N, P, U> {}
118
119impl<const N: usize, const P: bool> StringT for const_hex::Buffer<N, P> {
120    #[inline]
121    fn encode_to_buf(self, string: &mut Vec<u8>) {
122        string.extend(self.as_bytes());
123    }
124
125    #[inline]
126    fn encode_to_buf_with_separator(self, string: &mut Vec<u8>, separator: &str) {
127        string.extend(self.as_bytes());
128        string.extend(separator.as_bytes());
129    }
130
131    #[inline]
132    fn encode_to_bytes_buf(self, string: &mut bytes::BytesMut) {
133        string.extend(self.as_bytes());
134    }
135
136    #[inline]
137    fn encode_to_bytes_buf_with_separator(self, string: &mut bytes::BytesMut, separator: &str) {
138        string.extend(self.as_bytes());
139        string.extend(separator.as_bytes());
140    }
141}
142
143impl<const N: usize, const P: bool> StringExtT for const_hex::Buffer<N, P> {}
144
145#[cfg(test)]
146mod test {
147    use crate::string::{HexStr, StringExtT};
148
149    #[test]
150    fn test() {
151        assert_eq!(
152            HexStr::<0>::new(&[0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07]).to_string_ext(),
153            ""
154        );
155        assert_eq!(
156            HexStr::<7>::new(&[0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07]).to_string_ext(),
157            "01020304050607"
158        );
159        assert_eq!(
160            HexStr::<8>::new(&[0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07]).to_string_ext(),
161            "0001020304050607"
162        );
163        assert_eq!(
164            HexStr::<9>::new(&[0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07]).to_string_ext(),
165            "000001020304050607"
166        );
167    }
168
169    #[test]
170    fn test_with_prefix() {
171        assert_eq!(
172            HexStr::<0>::new(&[0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07])
173                .set_with_prefix::<true>()
174                .to_string_ext(),
175            "0x"
176        );
177        assert_eq!(
178            HexStr::<7>::new(&[0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07])
179                .set_with_prefix::<true>()
180                .to_string_ext(),
181            "0x01020304050607"
182        );
183        assert_eq!(
184            HexStr::<8>::new(&[0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07])
185                .set_with_prefix::<true>()
186                .to_string_ext(),
187            "0x0001020304050607"
188        );
189        assert_eq!(
190            HexStr::<9>::new(&[0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07])
191                .set_with_prefix::<true>()
192                .to_string_ext(),
193            "0x000001020304050607"
194        );
195    }
196
197    #[test]
198    fn test_uppcase() {
199        assert_eq!(
200            HexStr::<7>::new(&[0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0xa7])
201                .set_with_prefix::<true>()
202                .set_uppercase::<true>()
203                .to_string_ext(),
204            "0x010203040506A7"
205        );
206        assert_eq!(
207            HexStr::<8>::new(&[0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0xa7])
208                .set_with_prefix::<true>()
209                .set_uppercase::<true>()
210                .to_string_ext(),
211            "0x00010203040506A7"
212        );
213        assert_eq!(
214            HexStr::<9>::new(&[0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0xa7])
215                .set_with_prefix::<true>()
216                .set_uppercase::<true>()
217                .to_string_ext(),
218            "0x0000010203040506A7"
219        );
220    }
221}