dig_urn_protocol/
bytes.rs1use core::fmt;
9
10#[derive(Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord)]
15pub struct Bytes32(pub [u8; 32]);
16
17impl Bytes32 {
18 pub fn from_hex(hex_str: &str) -> Result<Bytes32, InvalidBytes32> {
23 if hex_str.len() != 64 {
24 return Err(InvalidBytes32);
25 }
26 let mut out = [0u8; 32];
27 hex::decode_to_slice(hex_str, &mut out).map_err(|_| InvalidBytes32)?;
28 Ok(Bytes32(out))
29 }
30
31 pub fn to_hex(&self) -> String {
33 hex::encode(self.0)
34 }
35}
36
37impl From<[u8; 32]> for Bytes32 {
38 fn from(raw: [u8; 32]) -> Self {
39 Bytes32(raw)
40 }
41}
42
43impl fmt::Debug for Bytes32 {
44 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
45 write!(f, "Bytes32({})", self.to_hex())
46 }
47}
48
49impl fmt::Display for Bytes32 {
50 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
51 f.write_str(&self.to_hex())
52 }
53}
54
55#[derive(Debug, Clone, Copy, PartialEq, Eq)]
57pub struct InvalidBytes32;
58
59impl fmt::Display for InvalidBytes32 {
60 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
61 f.write_str("value must be exactly 64 hex digits (32 bytes)")
62 }
63}
64
65impl std::error::Error for InvalidBytes32 {}
66
67#[cfg(test)]
68mod tests {
69 use super::*;
70
71 #[test]
72 fn roundtrips_lowercase_hex() {
73 let h = "aabbccddeeff00112233445566778899aabbccddeeff00112233445566778899";
74 assert_eq!(Bytes32::from_hex(h).unwrap().to_hex(), h);
75 }
76
77 #[test]
78 fn normalizes_uppercase_to_lowercase() {
79 let upper = "AABB".to_string() + &"00".repeat(30);
80 let lower = "aabb".to_string() + &"00".repeat(30);
81 assert_eq!(Bytes32::from_hex(&upper).unwrap().to_hex(), lower);
82 }
83
84 #[test]
85 fn rejects_wrong_length() {
86 assert_eq!(Bytes32::from_hex("1111"), Err(InvalidBytes32));
87 assert_eq!(Bytes32::from_hex(&"11".repeat(33)), Err(InvalidBytes32));
88 }
89
90 #[test]
91 fn rejects_non_hex() {
92 assert_eq!(Bytes32::from_hex(&"zz".repeat(32)), Err(InvalidBytes32));
93 }
94
95 #[test]
96 fn from_array_and_display() {
97 let b = Bytes32::from([0x11u8; 32]);
98 assert_eq!(b.to_string(), "11".repeat(32));
99 assert!(format!("{b:?}").contains(&"11".repeat(32)));
100 }
101}