1use serde::{Deserialize, Deserializer, Serialize, Serializer};
7
8#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
10pub struct SiteRef(pub u16);
11
12#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
14pub struct WordRef(pub u16);
15
16#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
18pub struct ZonedWordRef {
19 pub zone_id: u8,
20 pub word_id: u16,
21}
22
23#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
25#[repr(u8)]
26pub enum Direction {
27 Forward = 0,
29 Backward = 1,
31}
32
33#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
35#[repr(u8)]
36pub enum MoveType {
37 SiteBus = 0,
39 WordBus = 1,
41 ZoneBus = 2,
43}
44
45#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
52pub struct LocationAddr {
53 pub zone_id: u32,
54 pub word_id: u32,
55 pub site_id: u32,
56}
57
58impl LocationAddr {
59 pub fn encode(&self) -> u64 {
63 ((self.zone_id as u8 as u64) << 56)
64 | ((self.word_id as u16 as u64) << 40)
65 | ((self.site_id as u16 as u64) << 24)
66 }
67
68 pub fn decode(bits: u64) -> Self {
70 Self {
71 zone_id: ((bits >> 56) & 0xFF) as u32,
72 word_id: ((bits >> 40) & 0xFFFF) as u32,
73 site_id: ((bits >> 24) & 0xFFFF) as u32,
74 }
75 }
76}
77
78impl Serialize for LocationAddr {
79 fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
80 serializer.serialize_u64(self.encode())
81 }
82}
83
84impl<'de> Deserialize<'de> for LocationAddr {
85 fn deserialize<D: Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
86 let bits = u64::deserialize(deserializer)?;
87 Ok(Self::decode(bits))
88 }
89}
90
91#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
101pub struct LaneAddr {
102 pub direction: Direction,
103 pub move_type: MoveType,
104 pub zone_id: u32,
105 pub word_id: u32,
106 pub site_id: u32,
107 pub bus_id: u32,
108}
109
110impl LaneAddr {
111 pub fn encode(&self) -> (u32, u32) {
113 let data0 = ((self.word_id as u16 as u32) << 16) | (self.site_id as u16 as u32);
114 let data1 = ((self.direction as u32) << 31)
115 | ((self.move_type as u32) << 29)
116 | ((self.zone_id as u8 as u32) << 21)
117 | (self.bus_id as u16 as u32);
118 (data0, data1)
119 }
120
121 pub fn encode_u64(&self) -> u64 {
123 let (d0, d1) = self.encode();
124 (d0 as u64) | ((d1 as u64) << 32)
125 }
126
127 pub fn decode(data0: u32, data1: u32) -> Self {
129 let direction = if (data1 >> 31) & 1 == 0 {
130 Direction::Forward
131 } else {
132 Direction::Backward
133 };
134 let mt_bits = (data1 >> 29) & 0x3;
135 let move_type = match mt_bits {
136 0 => MoveType::SiteBus,
137 1 => MoveType::WordBus,
138 2 => MoveType::ZoneBus,
139 _ => panic!("invalid move type bits: {}", mt_bits),
140 };
141 Self {
142 direction,
143 move_type,
144 zone_id: (data1 >> 21) & 0xFF,
145 word_id: (data0 >> 16) & 0xFFFF,
146 site_id: data0 & 0xFFFF,
147 bus_id: data1 & 0xFFFF,
148 }
149 }
150
151 pub fn decode_u64(bits: u64) -> Self {
153 Self::decode(bits as u32, (bits >> 32) as u32)
154 }
155}
156
157#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
164pub struct ZoneAddr {
165 pub zone_id: u32,
166}
167
168impl ZoneAddr {
169 pub fn encode(&self) -> u32 {
171 self.zone_id as u8 as u32
172 }
173
174 pub fn decode(bits: u32) -> Self {
176 Self {
177 zone_id: bits & 0xFF,
178 }
179 }
180}
181
182#[cfg(test)]
183mod tests {
184 use super::*;
185
186 #[test]
187 fn test_move_type_zone_bus() {
188 assert_eq!(MoveType::SiteBus as u8, 0);
189 assert_eq!(MoveType::WordBus as u8, 1);
190 assert_eq!(MoveType::ZoneBus as u8, 2);
191 }
192
193 #[test]
194 fn test_location_addr_64bit_round_trip() {
195 let addr = LocationAddr {
196 zone_id: 5,
197 word_id: 0x1234,
198 site_id: 0x5678,
199 };
200 let bits = addr.encode();
201 assert_eq!(LocationAddr::decode(bits), addr);
202 assert_eq!((bits >> 56) & 0xFF, 5);
203 assert_eq!((bits >> 40) & 0xFFFF, 0x1234);
204 assert_eq!((bits >> 24) & 0xFFFF, 0x5678);
205 assert_eq!(bits & 0xFFFFFF, 0);
206 }
207
208 #[test]
209 fn test_location_addr_zero() {
210 let addr = LocationAddr {
211 zone_id: 0,
212 word_id: 0,
213 site_id: 0,
214 };
215 assert_eq!(addr.encode(), 0u64);
216 assert_eq!(LocationAddr::decode(0), addr);
217 }
218
219 #[test]
220 fn test_lane_addr_round_trip() {
221 let addr = LaneAddr {
222 direction: Direction::Backward,
223 move_type: MoveType::WordBus,
224 zone_id: 0,
225 word_id: 0x1234,
226 site_id: 0x5678,
227 bus_id: 0x9ABC,
228 };
229 let (data0, data1) = addr.encode();
230 assert_eq!(LaneAddr::decode(data0, data1), addr);
231
232 assert_eq!((data0 >> 16) & 0xFFFF, 0x1234); assert_eq!(data0 & 0xFFFF, 0x5678); assert_eq!((data1 >> 31) & 1, 1); assert_eq!((data1 >> 29) & 0x3, 1); assert_eq!(data1 & 0xFFFF, 0x9ABC); }
241
242 #[test]
243 fn test_lane_addr_forward_sitebus() {
244 let addr = LaneAddr {
245 direction: Direction::Forward,
246 move_type: MoveType::SiteBus,
247 zone_id: 0,
248 word_id: 0,
249 site_id: 0,
250 bus_id: 1,
251 };
252 let (data0, data1) = addr.encode();
253 assert_eq!(data0, 0);
254 assert_eq!(data1, 1);
255 assert_eq!(LaneAddr::decode(data0, data1), addr);
256 }
257
258 #[test]
259 fn test_lane_addr_u64_round_trip() {
260 let addr = LaneAddr {
261 direction: Direction::Backward,
262 move_type: MoveType::WordBus,
263 zone_id: 0,
264 word_id: 1,
265 site_id: 0,
266 bus_id: 0,
267 };
268 let packed = addr.encode_u64();
269 assert_eq!(LaneAddr::decode_u64(packed), addr);
270 }
271
272 #[test]
273 fn test_lane_addr_with_zone_id() {
274 let addr = LaneAddr {
275 direction: Direction::Backward,
276 move_type: MoveType::ZoneBus,
277 zone_id: 7,
278 word_id: 0x1234,
279 site_id: 0x5678,
280 bus_id: 0x9ABC,
281 };
282 let (data0, data1) = addr.encode();
283 let decoded = LaneAddr::decode(data0, data1);
284 assert_eq!(decoded, addr);
285 assert_eq!((data0 >> 16) & 0xFFFF, 0x1234);
286 assert_eq!(data0 & 0xFFFF, 0x5678);
287 assert_eq!((data1 >> 31) & 1, 1);
288 assert_eq!((data1 >> 29) & 0x3, 2);
289 assert_eq!((data1 >> 21) & 0xFF, 7);
290 assert_eq!(data1 & 0xFFFF, 0x9ABC);
291 }
292
293 #[test]
294 fn test_zone_addr_round_trip() {
295 let addr = ZoneAddr { zone_id: 42 };
296 let bits = addr.encode();
297 assert_eq!(bits, 42);
298 assert_eq!(ZoneAddr::decode(bits), addr);
299 }
300
301 #[test]
302 fn test_zone_addr_max() {
303 let addr = ZoneAddr { zone_id: 0xFF };
304 let bits = addr.encode();
305 assert_eq!(bits, 0xFF);
306 assert_eq!(ZoneAddr::decode(bits), addr);
307 }
308
309 #[test]
310 fn test_site_ref_newtype() {
311 let s = SiteRef(42);
312 assert_eq!(s.0, 42);
313 let json = serde_json::to_string(&s).unwrap();
314 let deserialized: SiteRef = serde_json::from_str(&json).unwrap();
315 assert_eq!(s, deserialized);
316 }
317
318 #[test]
319 fn test_word_ref_newtype() {
320 let w = WordRef(100);
321 assert_eq!(w.0, 100);
322 let json = serde_json::to_string(&w).unwrap();
323 let deserialized: WordRef = serde_json::from_str(&json).unwrap();
324 assert_eq!(w, deserialized);
325 }
326
327 #[test]
328 fn test_zoned_word_ref() {
329 let zwr = ZonedWordRef {
330 zone_id: 3,
331 word_id: 42,
332 };
333 assert_eq!(zwr.zone_id, 3);
334 assert_eq!(zwr.word_id, 42);
335 let json = serde_json::to_string(&zwr).unwrap();
336 let deserialized: ZonedWordRef = serde_json::from_str(&json).unwrap();
337 assert_eq!(zwr, deserialized);
338 }
339}