array_bytes/hex/
hexify.rs

1// core
2use core::{mem, str};
3// self
4use crate::prelude::*;
5
6const HEX_CHARS: &[u8; 16] = b"0123456789abcdef";
7const HEX_CHARS_UPPER: &[u8; 16] = b"0123456789ABCDEF";
8
9/// Hexify `Self`.
10///
11/// # Examples
12/// ```
13/// use array_bytes::Hexify;
14///
15/// // Unsigned.
16/// assert_eq!(52_u8.hexify(), "34");
17/// assert_eq!(520_u16.hexify_upper(), "208");
18/// assert_eq!(5_201_314_u32.hexify_prefixed(), "0x4f5da2");
19/// assert_eq!(5_201_314_u64.hexify_prefixed_upper(), "0x4F5DA2");
20/// assert_eq!(5_201_314_u128.hexify(), "4f5da2");
21/// assert_eq!(5_201_314_usize.hexify_upper(), "4F5DA2");
22/// // `[u8; N]`.
23/// assert_eq!(*b"Love Jane Forever".hexify(), String::from("4c6f7665204a616e6520466f7265766572"));
24/// // `&[u8; N]`.
25/// assert_eq!(
26/// 	b"Love Jane Forever".hexify_upper(),
27/// 	String::from("4C6F7665204A616E6520466F7265766572")
28/// );
29/// // `&[u8]`.
30/// assert_eq!(
31/// 	b"Love Jane Forever".as_slice().hexify_prefixed(),
32/// 	String::from("0x4c6f7665204a616e6520466f7265766572")
33/// );
34/// // `Vec<u8>`.
35/// assert_eq!(
36/// 	b"Love Jane Forever".to_vec().hexify_prefixed_upper(),
37/// 	String::from("0x4C6F7665204A616E6520466F7265766572")
38/// );
39/// // `&Vec<u8>`.
40/// assert_eq!(
41/// 	(&b"Love Jane Forever".to_vec()).hexify(),
42/// 	String::from("4c6f7665204a616e6520466f7265766572")
43/// );
44/// ```
45pub trait Hexify {
46	/// Hexify `Self`.
47	fn hexify(&self) -> String;
48
49	/// Hexify `Self` with uppercase.
50	fn hexify_upper(&self) -> String;
51
52	/// Hexify `Self` with `0x` prefix.
53	fn hexify_prefixed(&self) -> String;
54
55	/// Hexify `Self` with `0x` prefix and uppercase.
56	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		// The capacity is fixed, it's safe to set the length; qed.
139		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		// All the bytes are looked up in the map, it's safe to convert to string; qed.
156		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		// The capacity is fixed, it's safe to set the length; qed.
167		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		// All the bytes are looked up in the map, it's safe to convert to string; qed.
184		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	// Unsigned.
218	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	// `[u8; N]`.
225	assert_eq!(*b"Love Jane Forever".hexify(), String::from("4c6f7665204a616e6520466f7265766572"));
226	// `&[u8; N]`.
227	assert_eq!(
228		b"Love Jane Forever".hexify_upper(),
229		String::from("4C6F7665204A616E6520466F7265766572")
230	);
231	// `&[u8]`.
232	assert_eq!(
233		b"Love Jane Forever".as_slice().hexify_prefixed(),
234		String::from("0x4c6f7665204a616e6520466f7265766572")
235	);
236	// `Vec<u8>`.
237	assert_eq!(
238		b"Love Jane Forever".to_vec().hexify_prefixed_upper(),
239		String::from("0x4C6F7665204A616E6520466F7265766572")
240	);
241	// `&Vec<u8>`.
242	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
286/// Hexify the bytes which are already in hex.
287///
288/// This is useful when you are interacting with IO.
289///
290/// # Examples
291/// ```
292/// assert_eq!(
293/// 	array_bytes::hexify_hex_bytes(b"4c6f7665204a616e6520466f7265766572"),
294/// 	Ok("4c6f7665204a616e6520466f7265766572"),
295/// );
296/// ```
297pub 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		// Validated in previous step, never fails here; qed.
306		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}