array_bytes/hex/
hexify.rs1use core::{mem, str};
3use crate::prelude::*;
5
6const HEX_CHARS: &[u8; 16] = b"0123456789abcdef";
7const HEX_CHARS_UPPER: &[u8; 16] = b"0123456789ABCDEF";
8
9pub trait Hexify {
46 fn hexify(&self) -> String;
48
49 fn hexify_upper(&self) -> String;
51
52 fn hexify_prefixed(&self) -> String;
54
55 fn hexify_prefixed_upper(&self) -> String;
57}
58macro_rules! hexify_unsigned {
59 ($self:expr, $map:expr) => {{
60 match $self.highest_set_bit() {
61 None => "0".into(),
62 Some(high_bit) => {
63 let high_nibble = high_bit / 4;
64 let nibble_count = high_nibble + 1;
65 let mut hex = String::with_capacity(nibble_count as _);
66
67 for nibble in (0..=high_nibble).rev() {
68 let shift = nibble * 4;
69 let digit = (($self >> shift) & 0xF) as usize;
70
71 hex.push($map[digit] as _);
72 }
73
74 hex
75 },
76 }
77 }};
78}
79macro_rules! hexify_unsigned_prefixed {
80 ($self:expr, $map:expr) => {{
81 match $self.highest_set_bit() {
82 None => "0x0".into(),
83 Some(high_bit) => {
84 let high_nibble = high_bit / 4;
85 let nibble_count = high_nibble + 1;
86 let mut hex = String::with_capacity(2 + nibble_count as usize);
87
88 hex.push_str("0x");
89
90 for nibble in (0..=high_nibble).rev() {
91 let shift = nibble * 4;
92 let digit = (($self >> shift) & 0xF) as usize;
93
94 hex.push($map[digit] as _);
95 }
96
97 hex
98 },
99 }
100 }};
101}
102macro_rules! impl_hexify_for_unsigned {
103 ($($t:ty,)+) => {
104 $(
105 impl Hexify for $t {
106 fn hexify(&self) -> String {
107 hexify_unsigned!(self, HEX_CHARS)
108 }
109
110 fn hexify_upper(&self) -> String {
111 hexify_unsigned!(self, HEX_CHARS_UPPER)
112 }
113
114 fn hexify_prefixed(&self) -> String {
115 hexify_unsigned_prefixed!(self, HEX_CHARS)
116 }
117
118 fn hexify_prefixed_upper(&self) -> String {
119 hexify_unsigned_prefixed!(self, HEX_CHARS_UPPER)
120 }
121 }
122 )+
123 };
124}
125impl_hexify_for_unsigned! {
126 usize,
127 u8,
128 u16,
129 u32,
130 u64,
131 u128,
132}
133macro_rules! hexify {
134 ($self:expr, $map:expr) => {{
135 let cap = $self.len() * 2;
136 let mut hex_bytes = <SmallVec<[u8; 128]>>::with_capacity(cap);
137
138 unsafe {
140 hex_bytes.set_len(cap);
141 }
142
143 let hex_ptr = hex_bytes.as_mut_ptr();
144
145 for (i, &byte) in $self.iter().enumerate() {
146 let high = $map[(byte >> 4) as usize];
147 let low = $map[(byte & 0x0f) as usize];
148
149 unsafe {
150 *hex_ptr.add(i * 2) = high;
151 *hex_ptr.add(i * 2 + 1) = low;
152 }
153 }
154
155 unsafe { String::from_utf8_unchecked(hex_bytes.into_vec()) }
157 }};
158}
159macro_rules! hexify_prefixed {
160 ($self:expr, $map:expr) => {{
161 let cap = 2 + $self.len() * 2;
162 let mut hex_bytes = <SmallVec<[u8; 128]>>::with_capacity(cap);
163
164 hex_bytes.extend_from_slice(b"0x");
165
166 unsafe {
168 hex_bytes.set_len(cap);
169 }
170
171 let hex_ptr = unsafe { hex_bytes.as_mut_ptr().add(2) };
172
173 for (i, &byte) in $self.iter().enumerate() {
174 let high = $map[(byte >> 4) as usize];
175 let low = $map[(byte & 0x0f) as usize];
176
177 unsafe {
178 *hex_ptr.add(i * 2) = high;
179 *hex_ptr.add(i * 2 + 1) = low;
180 }
181 }
182
183 unsafe { String::from_utf8_unchecked(hex_bytes.into_vec()) }
185 }};
186}
187macro_rules! hexify_bytes_fns {
188 () => {
189 fn hexify(&self) -> String {
190 hexify!(self, HEX_CHARS)
191 }
192
193 fn hexify_upper(&self) -> String {
194 hexify!(self, HEX_CHARS_UPPER)
195 }
196
197 fn hexify_prefixed(&self) -> String {
198 hexify_prefixed!(self, HEX_CHARS)
199 }
200
201 fn hexify_prefixed_upper(&self) -> String {
202 hexify_prefixed!(self, HEX_CHARS_UPPER)
203 }
204 };
205}
206impl<const N: usize> Hexify for [u8; N] {
207 hexify_bytes_fns! {}
208}
209impl Hexify for [u8] {
210 hexify_bytes_fns! {}
211}
212impl Hexify for Vec<u8> {
213 hexify_bytes_fns! {}
214}
215#[test]
216fn hexify_should_work() {
217 assert_eq!(52_u8.hexify(), "34");
219 assert_eq!(520_u16.hexify_upper(), "208");
220 assert_eq!(5_201_314_u32.hexify_prefixed(), "0x4f5da2");
221 assert_eq!(5_201_314_u64.hexify_prefixed_upper(), "0x4F5DA2");
222 assert_eq!(5_201_314_u128.hexify(), "4f5da2");
223 assert_eq!(5_201_314_usize.hexify_upper(), "4F5DA2");
224 assert_eq!(*b"Love Jane Forever".hexify(), String::from("4c6f7665204a616e6520466f7265766572"));
226 assert_eq!(
228 b"Love Jane Forever".hexify_upper(),
229 String::from("4C6F7665204A616E6520466F7265766572")
230 );
231 assert_eq!(
233 b"Love Jane Forever".as_slice().hexify_prefixed(),
234 String::from("0x4c6f7665204a616e6520466f7265766572")
235 );
236 assert_eq!(
238 b"Love Jane Forever".to_vec().hexify_prefixed_upper(),
239 String::from("0x4C6F7665204A616E6520466F7265766572")
240 );
241 assert_eq!(
243 (&b"Love Jane Forever".to_vec()).hexify(),
244 String::from("4c6f7665204a616e6520466f7265766572")
245 );
246}
247
248trait HighestSetBit {
249 fn highest_set_bit(self) -> Option<u32>;
250}
251macro_rules! impl_highest_set_bit {
252 ($($t:ty),+ $(,)?) => {
253 $(
254 impl HighestSetBit for $t {
255 fn highest_set_bit(self) -> Option<u32> {
256 if self == 0 {
257 None
258 } else {
259 let n_bits = (mem::size_of::<$t>() as u32) * 8;
260
261 Some(n_bits - 1 - self.leading_zeros())
262 }
263 }
264 }
265 )+
266 }
267}
268impl_highest_set_bit! {
269 u8,
270 u16,
271 u32,
272 u64,
273 u128,
274 usize
275}
276#[test]
277fn highest_set_bit_should_work() {
278 assert_eq!(0_u8.highest_set_bit(), None);
279 assert_eq!(1_u16.highest_set_bit(), Some(0));
280 assert_eq!(2_u32.highest_set_bit(), Some(1));
281 assert_eq!(4_u64.highest_set_bit(), Some(2));
282 assert_eq!(8_u128.highest_set_bit(), Some(3));
283 assert_eq!(16_usize.highest_set_bit(), Some(4));
284}
285
286pub fn hexify_hex_bytes(bytes: &[u8]) -> Result<&str> {
298 for (i, byte) in bytes.iter().enumerate().skip(if bytes.starts_with(b"0x") { 2 } else { 0 }) {
299 if !byte.is_ascii_hexdigit() {
300 Err(Error::InvalidCharacter { character: *byte as _, index: i })?;
301 }
302 }
303
304 Ok(
305 unsafe { str::from_utf8_unchecked(bytes) },
307 )
308}
309#[test]
310fn hexify_hex_bytes_should_work() {
311 assert_eq!(
312 hexify_hex_bytes(b"4c6f7665204a616e6520466f7265766572"),
313 Ok("4c6f7665204a616e6520466f7265766572"),
314 );
315 assert_eq!(
316 hexify_hex_bytes(b"4C6F7665204A616E6520466F7265766572"),
317 Ok("4C6F7665204A616E6520466F7265766572"),
318 );
319 assert_eq!(
320 hexify_hex_bytes(b"0x4c6f7665204a616e6520466f7265766572"),
321 Ok("0x4c6f7665204a616e6520466f7265766572"),
322 );
323 assert_eq!(
324 hexify_hex_bytes(b"0x4C6F7665204A616E6520466F7265766572"),
325 Ok("0x4C6F7665204A616E6520466F7265766572"),
326 );
327}