|
1 | | -pub struct HexDisplay<T>(T); |
| 1 | +pub struct HexDisplay([u8; 32]); |
2 | 2 |
|
3 | | -impl<T: AsRef<[u8]>> core::fmt::Display for HexDisplay<T> { |
| 3 | +impl core::fmt::Debug for HexDisplay { |
4 | 4 | fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { |
5 | | - for b in self.0.as_ref() { |
6 | | - write!(f, "{b:02x}")?; |
7 | | - } |
8 | | - Ok(()) |
| 5 | + std::fmt::Display::fmt(self, f) |
9 | 6 | } |
10 | 7 | } |
11 | 8 |
|
12 | | -pub trait HexDisplayExt: AsRef<[u8]> { |
13 | | - fn hex_display(self) -> HexDisplay<Self> |
14 | | - where |
15 | | - Self: Sized, |
16 | | - { |
17 | | - HexDisplay(self) |
| 9 | +impl core::fmt::Display for HexDisplay { |
| 10 | + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { |
| 11 | + const CHARSET: &[u8; 16] = b"0123456789abcdef"; |
| 12 | + |
| 13 | + let mut buf = [0u8; 64]; |
| 14 | + // SAFETY: 64 is evenly divisible by 2 |
| 15 | + unsafe { buf.as_chunks_unchecked_mut::<2>() } |
| 16 | + .iter_mut() |
| 17 | + .zip(self.0.as_ref()) |
| 18 | + .for_each(|(slot, &byte)| { |
| 19 | + slot[0] = CHARSET[(byte >> 4) as usize]; |
| 20 | + slot[1] = CHARSET[(byte & 0x0F) as usize]; |
| 21 | + }); |
| 22 | + |
| 23 | + // SAFETY: buf only contains valid ASCII hex characters |
| 24 | + let buf = unsafe { core::str::from_utf8_unchecked(&buf) }; |
| 25 | + |
| 26 | + f.pad(buf) |
18 | 27 | } |
19 | 28 | } |
20 | 29 |
|
21 | | -impl<T: AsRef<[u8]>> HexDisplayExt for T {} |
| 30 | +pub trait HexDisplayExt { |
| 31 | + fn hex_display(self) -> HexDisplay; |
| 32 | +} |
| 33 | + |
| 34 | +impl<T: Into<[u8; 32]>> HexDisplayExt for T { |
| 35 | + fn hex_display(self) -> HexDisplay { |
| 36 | + HexDisplay(self.into()) |
| 37 | + } |
| 38 | +} |
0 commit comments