Skip to main content

yevm_misc/
hex.rs

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}