1use std::fmt;
2
3#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
4pub struct Hex<const N: usize>([u8; N]);
5
6impl<const N: usize> Hex<N> {
7 pub const N: usize = N;
8 pub const ZERO: Self = Self::zero();
9 pub const ONE: Self = Self::one();
10 pub const MAX: Self = Self::max();
11
12 pub const fn new(bytes: [u8; N]) -> Self {
13 Self(bytes)
14 }
15
16 pub const fn zero() -> Self {
17 Self([0; N])
18 }
19
20 pub const fn one() -> Self {
21 let mut buf = [0; N];
22 buf[N - 1] = 1;
23 Self(buf)
24 }
25
26 pub const fn max() -> Self {
27 Self([0xff; N])
28 }
29
30 pub fn is_zero(&self) -> bool {
31 self == &Self::ZERO
32 }
33
34 pub fn as_usize(&self) -> usize {
35 const K: usize = size_of::<usize>();
36 let mut b = [0u8; K];
37 b.copy_from_slice(self.to::<K>().as_ref());
38 usize::from_be_bytes(b)
39 }
40
41 pub fn as_usize_checked(&self) -> Option<usize> {
42 const K: usize = size_of::<usize>();
43 if self.0[..N - K].iter().any(|&b| b != 0) {
44 return None;
45 }
46 Some(self.as_usize())
47 }
48
49 pub fn as_u128(&self) -> u128 {
50 const K: usize = size_of::<u128>();
51 let mut b = [0u8; K];
52 b.copy_from_slice(self.to::<K>().as_ref());
53 u128::from_be_bytes(b)
54 }
55
56 pub fn as_u64(&self) -> u64 {
57 const K: usize = size_of::<u64>();
58 let mut b = [0u8; K];
59 b.copy_from_slice(self.to::<K>().as_ref());
60 u64::from_be_bytes(b)
61 }
62
63 pub fn as_u32(&self) -> u32 {
64 const K: usize = size_of::<u32>();
65 let mut b = [0u8; K];
66 b.copy_from_slice(self.to::<K>().as_ref());
67 u32::from_be_bytes(b)
68 }
69
70 pub fn as_u16(&self) -> u16 {
71 const K: usize = size_of::<u16>();
72 let mut b = [0u8; K];
73 b.copy_from_slice(self.to::<K>().as_ref());
74 u16::from_be_bytes(b)
75 }
76
77 pub fn as_u8(&self) -> u8 {
78 self.0[N - 1]
79 }
80}
81
82impl<const N: usize> AsRef<[u8]> for Hex<N> {
83 fn as_ref(&self) -> &[u8] {
84 &self.0
85 }
86}
87
88impl<const N: usize> From<&[u8]> for Hex<N> {
89 fn from(value: &[u8]) -> Self {
90 assert!(value.len() <= N, "data loss detected");
91 let mut buffer = [0u8; N];
92 let take = value.len().min(N);
93 let skip = N - take;
94 buffer[skip..].copy_from_slice(&value[..take]);
95 Self(buffer)
96 }
97}
98
99impl<const N: usize> From<usize> for Hex<N> {
100 fn from(value: usize) -> Self {
101 Self::from(&value.to_be_bytes()[..])
102 }
103}
104
105impl<const N: usize> From<u128> for Hex<N> {
106 fn from(value: u128) -> Self {
107 Self::from(&value.to_be_bytes()[..])
108 }
109}
110
111impl<const N: usize> From<u64> for Hex<N> {
112 fn from(value: u64) -> Self {
113 Self::from(&value.to_be_bytes()[..])
114 }
115}
116
117impl<const N: usize> From<u32> for Hex<N> {
118 fn from(value: u32) -> Self {
119 Self::from(&value.to_be_bytes()[..])
120 }
121}
122
123impl<const N: usize> From<u16> for Hex<N> {
124 fn from(value: u16) -> Self {
125 Self::from(&value.to_be_bytes()[..])
126 }
127}
128
129impl<const N: usize> From<u8> for Hex<N> {
130 fn from(value: u8) -> Self {
131 Self::from(&[value][..])
132 }
133}
134
135impl<const N: usize> From<i32> for Hex<N> {
136 fn from(value: i32) -> Self {
137 Self::from(value.max(0) as u32)
138 }
139}
140
141impl<const N: usize> From<i64> for Hex<N> {
142 fn from(value: i64) -> Self {
143 Self::from(value.max(0) as u64)
144 }
145}
146
147impl<const N: usize> Hex<N> {
148 pub fn to<const M: usize>(self) -> Hex<M> {
149 let mut buffer = [0; M];
150 if M > N {
151 buffer[(M - N)..].copy_from_slice(&self.0);
152 } else {
153 buffer[..].copy_from_slice(&self.0[(N - M)..]);
154 }
155 Hex(buffer)
156 }
157}
158
159impl<const N: usize> Default for Hex<N> {
160 fn default() -> Self {
161 Self([0; N])
162 }
163}
164
165impl<const N: usize> fmt::Display for Hex<N> {
166 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
167 f.write_str("0x")?;
168 for b in &self.0 {
169 write!(f, "{:02x}", b)?;
170 }
171 Ok(())
172 }
173}
174
175impl<const N: usize> fmt::Debug for Hex<N> {
176 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
177 f.write_str("0x")?;
178 for b in &self.0 {
179 write!(f, "{:02x}", b)?;
180 }
181 Ok(())
182 }
183}
184
185impl<const N: usize> serde::Serialize for Hex<N> {
186 fn serialize<S: serde::Serializer>(&self, s: S) -> Result<S::Ok, S::Error> {
187 s.collect_str(self)
188 }
189}
190
191impl<'de, const N: usize> serde::Deserialize<'de> for Hex<N> {
192 fn deserialize<D: serde::Deserializer<'de>>(d: D) -> Result<Self, D::Error> {
193 let s = String::deserialize(d)?;
194 let hex = s.strip_prefix("0x").unwrap_or(&s);
195 let ok = hex.as_bytes().iter().all(|&c| c.is_ascii_hexdigit());
196 if !ok {
197 return Err(serde::de::Error::custom("hex literal invalid"));
198 }
199 if hex.len() > 2 * N {
200 return Err(serde::de::Error::custom("hex literal too long"));
201 }
202 let bytes = parse(&s);
203 Ok(Self(bytes))
204 }
205}
206
207pub fn parse_vec(s: &str) -> Result<Vec<u8>, &'static str> {
208 let skip = if s.len() >= 2 && s.as_bytes()[0] == b'0' && s.as_bytes()[1] == b'x' {
209 2
210 } else {
211 0
212 };
213 let len = s.len() - skip;
214 let n = len.div_ceil(2);
215 let offset = n * 2 - len;
216 let mut ret = vec![0u8; n];
217 for j in skip..s.len() {
218 let c = s.as_bytes()[j];
219 let d = match c {
220 b'0'..=b'9' => c - b'0',
221 b'a'..=b'f' => c - b'a' + 10,
222 b'A'..=b'F' => c - b'A' + 10,
223 _ => return Err("hex literal invalid"),
224 };
225 let k = j - skip;
226 let i = offset + k;
227 let b = i / 2;
228 if i.is_multiple_of(2) {
229 ret[b] = d << 4;
230 } else {
231 ret[b] |= d;
232 }
233 }
234 Ok(ret)
235}
236
237pub const fn parse<const N: usize>(s: &str) -> [u8; N] {
238 let skip = if s.len() >= 2 && s.as_bytes()[0] == b'0' && s.as_bytes()[1] == b'x' {
239 2
240 } else {
241 0
242 };
243 if s.len() - skip > N * 2 {
244 panic!("hex literal too long");
245 }
246 let len = s.len() - skip;
247 let offset = N * 2 - len;
248 let mut ret = [0u8; N];
249 let mut j = skip;
250 while j < s.len() {
251 let c = s.as_bytes()[j];
252 let d = match c {
253 b'0'..=b'9' => c - b'0',
254 b'a'..=b'f' => c - b'a' + 10,
255 b'A'..=b'F' => c - b'A' + 10,
256 _ => panic!("hex literal invalid"),
257 };
258 let i = offset + (j - skip);
259 let b = i / 2;
260 if i.is_multiple_of(2) {
261 ret[b] = d << 4;
262 } else {
263 ret[b] |= d;
264 }
265 j += 1;
266 }
267 ret
268}
269
270#[cfg(test)]
271mod tests {
272 use super::*;
273
274 #[test]
275 fn test_parse_empty() {
276 assert_eq!(parse::<4>(""), [0x00, 0x00, 0x00, 0x00]);
277 }
278
279 #[test]
280 fn test_parse_single_nibble() {
281 assert_eq!(parse::<1>("f"), [0x0f]);
282 assert_eq!(parse::<4>("f"), [0x00, 0x00, 0x00, 0x0f]);
283 }
284
285 #[test]
286 fn test_parse_single_byte() {
287 assert_eq!(parse::<1>("ff"), [0xff]);
288 assert_eq!(parse::<4>("ff"), [0x00, 0x00, 0x00, 0xff]);
289 }
290
291 #[test]
292 fn test_parse_exact() {
293 assert_eq!(parse::<4>("deadbeef"), [0xde, 0xad, 0xbe, 0xef]);
294 assert_eq!(parse::<4>("00000000"), [0x00, 0x00, 0x00, 0x00]);
295 assert_eq!(parse::<4>("ffffffff"), [0xff, 0xff, 0xff, 0xff]);
296 }
297
298 #[test]
299 fn test_parse_short() {
300 assert_eq!(parse::<4>("beef"), [0x00, 0x00, 0xbe, 0xef]);
301 assert_eq!(parse::<4>("1"), [0x00, 0x00, 0x00, 0x01]);
302 }
303
304 #[test]
305 fn test_parse_with_prefix() {
306 assert_eq!(parse::<4>("0xdeadbeef"), [0xde, 0xad, 0xbe, 0xef]);
307 assert_eq!(parse::<1>("0xff"), [0xff]);
308 assert_eq!(parse::<4>("0xbeef"), [0x00, 0x00, 0xbe, 0xef]);
309 assert_eq!(parse::<4>("0x1"), [0x00, 0x00, 0x00, 0x01]);
310 }
311
312 #[test]
313 #[should_panic]
314 fn test_parse_too_long() {
315 let _ = parse::<4>("deadbeef00");
316 }
317
318 #[test]
319 #[should_panic]
320 fn test_parse_too_long_with_prefix() {
321 let _ = parse::<4>("0xdeadbeef00");
322 }
323
324 #[test]
325 #[should_panic]
326 fn test_parse_invalid_char() {
327 let _ = parse::<4>("xyz0");
328 }
329
330 #[test]
331 fn test_display() {
332 let h = Hex::<4>::from(&[0x00, 0x00, 0xbe, 0xef][..]);
333 assert_eq!(h.to_string(), "0x0000beef");
334 let z = Hex::<4>::ZERO;
335 assert_eq!(z.to_string(), "0x00000000");
336 let one = Hex::<4>::ONE;
337 assert_eq!(one.to_string(), "0x00000001");
338 }
339
340 #[test]
341 fn test_debug() {
342 let h = Hex::<4>::from(&[0x00, 0x00, 0xbe, 0xef][..]);
343 assert_eq!(format!("{:?}", h), "0x0000beef");
344 }
345
346 #[test]
347 fn test_serde_roundtrip() {
348 let h = Hex::<4>::from(&[0xde, 0xad, 0xbe, 0xef][..]);
349 let s = serde_json::to_string(&h).unwrap();
350 let h2: Hex<4> = serde_json::from_str(&s).unwrap();
351 assert_eq!(h, h2);
352 }
353
354 #[test]
355 fn test_parse_vec_empty() {
356 assert_eq!(parse_vec("").unwrap(), vec![] as Vec<u8>);
357 assert_eq!(parse_vec("0x").unwrap(), vec![] as Vec<u8>);
358 }
359
360 #[test]
361 fn test_parse_vec_no_prefix() {
362 assert_eq!(parse_vec("abcd").unwrap(), vec![0xab, 0xcd]);
363 assert_eq!(parse_vec("ff").unwrap(), vec![0xff]);
364 assert_eq!(parse_vec("1").unwrap(), vec![0x01]);
365 assert_eq!(parse_vec("deadbeef").unwrap(), vec![0xde, 0xad, 0xbe, 0xef]);
366 }
367
368 #[test]
369 fn test_parse_vec_with_prefix() {
370 assert_eq!(parse_vec("0xabcd").unwrap(), vec![0xab, 0xcd]);
371 assert_eq!(parse_vec("0xff").unwrap(), vec![0xff]);
372 assert_eq!(parse_vec("0x1").unwrap(), vec![0x01]);
373 assert_eq!(
374 parse_vec("0xdeadbeef").unwrap(),
375 vec![0xde, 0xad, 0xbe, 0xef]
376 );
377 }
378
379 #[test]
380 fn test_parse_vec_odd_nibble() {
381 assert_eq!(parse_vec("abc").unwrap(), vec![0x0a, 0xbc]);
382 assert_eq!(parse_vec("0xabc").unwrap(), vec![0x0a, 0xbc]);
383 }
384
385 #[test]
386 fn test_parse_vec_invalid_char() {
387 assert!(parse_vec("0xgg").is_err());
388 }
389}