byte_wrapper/
hex_slice.rs1use core::fmt::{self, Write};
7
8#[derive(PartialEq, Eq, PartialOrd, Ord, Hash)]
31#[repr(transparent)]
32pub struct HexSlice([u8]);
33
34impl HexSlice {
35 #[inline]
37 #[must_use]
38 pub const fn new(bytes: &[u8]) -> &Self {
39 unsafe { &*(bytes as *const [u8] as *const Self) }
48 }
49
50 #[inline]
52 #[must_use]
53 pub const fn as_bytes(&self) -> &[u8] {
54 &self.0
55 }
56}
57
58pub(crate) struct HexDisplay<'a>(pub(crate) &'a [u8]);
63
64impl fmt::Display for HexDisplay<'_> {
65 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
66 for byte in self.0 {
67 write!(f, "{byte:02x}")?;
68 }
69 Ok(())
70 }
71}
72
73impl fmt::Debug for HexDisplay<'_> {
74 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
75 fmt::Display::fmt(self, f)
76 }
77}
78
79fn fmt_hex_padded(
84 bytes: &[u8],
85 f: &mut fmt::Formatter<'_>,
86 write_byte: fn(&mut fmt::Formatter<'_>, u8) -> fmt::Result,
87) -> fmt::Result {
88 let content_len = bytes.len() * 2;
89
90 match f.width() {
91 Some(width) if width > content_len => {
92 let padding = width - content_len;
93 let fill = f.fill();
94 let (pre, post) = match f.align() {
95 Some(fmt::Alignment::Left) => (0, padding),
96 Some(fmt::Alignment::Right) | None => (padding, 0),
97 Some(fmt::Alignment::Center) => {
98 (padding / 2, padding - padding / 2)
99 }
100 };
101 for _ in 0..pre {
102 f.write_char(fill)?;
103 }
104 for &byte in bytes {
105 write_byte(f, byte)?;
106 }
107 for _ in 0..post {
108 f.write_char(fill)?;
109 }
110 Ok(())
111 }
112 Some(_) | None => {
113 for &byte in bytes {
114 write_byte(f, byte)?;
115 }
116 Ok(())
117 }
118 }
119}
120
121impl fmt::Debug for HexSlice {
122 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
123 f.debug_tuple("HexSlice").field(&HexDisplay(&self.0)).finish()
124 }
125}
126
127impl fmt::Display for HexSlice {
128 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
129 fmt::LowerHex::fmt(self, f)
130 }
131}
132
133impl fmt::LowerHex for HexSlice {
134 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
135 fmt_hex_padded(&self.0, f, |f, b| write!(f, "{b:02x}"))
136 }
137}
138
139impl fmt::UpperHex for HexSlice {
140 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
141 fmt_hex_padded(&self.0, f, |f, b| write!(f, "{b:02X}"))
142 }
143}
144
145impl core::ops::Deref for HexSlice {
146 type Target = [u8];
147
148 #[inline]
149 fn deref(&self) -> &Self::Target {
150 &self.0
151 }
152}
153
154impl AsRef<[u8]> for HexSlice {
155 #[inline]
156 fn as_ref(&self) -> &[u8] {
157 &self.0
158 }
159}
160
161impl AsRef<HexSlice> for HexSlice {
162 #[inline]
163 fn as_ref(&self) -> &HexSlice {
164 self
165 }
166}
167
168#[cfg(feature = "serde")]
169mod serde_impls {
170 use super::{HexDisplay, HexSlice};
171
172 #[cfg_attr(doc_cfg, doc(cfg(feature = "serde")))]
173 impl serde_core::Serialize for HexSlice {
174 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
175 where
176 S: serde_core::Serializer,
177 {
178 if serializer.is_human_readable() {
179 serializer.collect_str(&HexDisplay(&self.0))
180 } else {
181 serializer.serialize_bytes(&self.0)
182 }
183 }
184 }
185}