1use std::convert::Infallible;
2use std::fmt::{self, Write};
3use std::str::FromStr;
4
5#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
6pub struct Address(u64);
7
8#[derive(Debug, thiserror::Error)]
9#[error("couldn't parse address")]
10pub struct AddressParseError;
11
12impl Address {
13 pub const fn from_u64(inner: u64) -> Self {
14 Self(inner)
15 }
16
17 pub const fn into_u64(self) -> u64 {
18 self.0
19 }
20}
21
22impl TryFrom<u64> for Address {
23 type Error = Infallible;
24
25 fn try_from(value: u64) -> Result<Self, Self::Error> {
26 Ok(Self(value))
27 }
28}
29
30impl FromStr for Address {
31 type Err = AddressParseError;
32
33 fn from_str(s: &str) -> Result<Self, Self::Err> {
34 let address = address_str::from_str(s).ok_or(AddressParseError)?;
35 Ok(Self(address))
36 }
37}
38
39impl fmt::Display for Address {
40 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
41 for c in address_str::to_chars(self.0) {
42 f.write_char(c)?;
43 }
44 Ok(())
45 }
46}
47impl fmt::Debug for Address {
48 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
49 fmt::Display::fmt(self, f)
50 }
51}
52
53impl serde::Serialize for Address {
54 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
55 where
56 S: serde::Serializer,
57 {
58 self.to_string().serialize(serializer)
59 }
60}
61impl<'de> serde::Deserialize<'de> for Address {
62 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
63 where
64 D: serde::Deserializer<'de>,
65 {
66 String::deserialize(deserializer)?
67 .parse()
68 .map_err(<D::Error as serde::de::Error>::custom)
69 }
70}
71
72mod address_str {
73 const CH_GAP: char = ':';
74 const CH_OPEN: char = '<';
75 const CH_CLOSE: char = '>';
76
77 fn digits(mut u: u64) -> [u8; 16] {
78 const MASK: u64 = 0xF000_0000_0000_0000;
79 const OFFSET: u32 = u64::BITS - 4;
80
81 let mut out = [0u8; 16];
82 for d in out.iter_mut() {
83 *d = ((u & MASK) >> OFFSET) as u8;
84 assert!(*d <= 0xF);
85 u <<= 4;
86 }
87
88 out
89 }
90
91 pub(super) fn from_str(s: &str) -> Option<u64> {
92 let bytes = s.as_bytes();
93 if (bytes.first().copied(), bytes.last().copied())
94 != (Some(CH_OPEN as u8), Some(CH_CLOSE as u8))
95 {
96 return None
97 }
98 let bytes = &bytes[1..bytes.len() - 1];
99
100 let mut gap_len = Some(16usize.checked_sub(bytes.len())?);
101
102 let mut out = 0u64;
103
104 for b in bytes.iter().copied() {
105 out <<= 4;
106
107 let c = b as char;
108
109 if c == CH_GAP {
110 let gap_len = gap_len.take()?;
111 out <<= (4 * gap_len) as u32
112 } else {
113 let d = c.to_digit(16)?;
114 out += d as u64;
115 }
116 }
117
118 Some(out)
119 }
120
121 pub(super) fn to_chars(u: u64) -> impl Iterator<Item = char> {
122 #[derive(Default, Clone, Copy)]
123 struct Span {
124 start: usize,
125 len: usize,
126 }
127
128 let digits = digits(u);
129
130 let mut this: Span = Default::default();
131 let mut best: Span = Default::default();
132
133 for (idx, d) in digits.iter().copied().enumerate() {
134 if d == 0 {
135 this.len += 1
136 } else {
137 if this.len > best.len {
138 best = this;
139 }
140 this = Span {
141 start: idx + 1,
142 len: 0,
143 };
144 }
145 }
146 if this.len > best.len {
147 best = this;
148 }
149
150 let left = digits
151 .into_iter()
152 .take(best.start)
153 .map(|d| char::from_digit(d as u32, 16).expect("should be within `0..=F`"));
154
155 let (center, resume_from) = if best.len > 1 {
156 (Some(CH_GAP), best.start + best.len)
157 } else {
158 (None, best.start)
159 };
160
161 let right = digits
162 .into_iter()
163 .skip(resume_from)
164 .map(|d| char::from_digit(d as u32, 16).expect("should be within `0..=F`"));
165
166 [CH_OPEN]
167 .into_iter()
168 .chain(left)
169 .chain(center)
170 .chain(right)
171 .chain([CH_CLOSE])
172 }
173
174 #[cfg(test)]
175 mod tests {
176 use super::*;
177
178 fn to_str(u: u64) -> String {
179 to_chars(u).collect()
180 }
181
182 #[test]
183 fn test_digits() {
184 assert_eq!(
185 [0xa, 0xa, 0xa, 0xa, 0xb, 0xa, 0xb, 0xe, 0xf, 0xa, 0xc, 0xe, 0xd, 0xe, 0xa, 0xd],
186 digits(0xAAAA_BABE_FACE_DEAD)
187 );
188 }
189
190 #[test]
191 fn test_to_str() {
192 assert_eq!(to_str(0xF0F0_F0F0_F0F0_F0F0), "<f0f0f0f0f0f0f0f0>");
193 assert_eq!(to_str(0xFF00_FF00_FF00_FF00), "<ff:ff00ff00ff00>");
194 assert_eq!(to_str(0xFF00_F000_FF00_FF00), "<ff00f:ff00ff00>");
195 assert_eq!(to_str(0xFF00_0000_FF00_FF00), "<ff:ff00ff00>");
196 assert_eq!(to_str(0xFF00_00FF_0000_FF00), "<ff:ff0000ff00>");
197 assert_eq!(to_str(0xFF00_0000_0000_0000), "<ff:>");
198 }
199
200 #[test]
201 fn test_from_str() {
202 assert_eq!(from_str("<f0f0f0f0f0f0f0f0>"), Some(0xF0F0_F0F0_F0F0_F0F0));
203 assert_eq!(from_str("<ff:ff00ff00ff00>"), Some(0xFF00_FF00_FF00_FF00));
204 assert_eq!(from_str("<ff00f:ff00ff00>"), Some(0xFF00_F000_FF00_FF00));
205 assert_eq!(from_str("<ff:ff00ff00>"), Some(0xFF00_0000_FF00_FF00));
206 assert_eq!(from_str("<ff:ff0000ff00>"), Some(0xFF00_00FF_0000_FF00));
207 assert_eq!(from_str("<ff:>"), Some(0xFF00_0000_0000_0000));
208 }
209 }
210}