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, PartialOrd, Ord, Hash)]
31#[repr(u8)]
32pub enum Direction {
33 Forward = 0,
35 Backward = 1,
37}
38
39#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
47#[repr(u8)]
48pub enum MoveType {
49 SiteBus = 0,
51 WordBus = 1,
53 ZoneBus = 2,
55}
56
57#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
64pub struct LocationAddr {
65 pub zone_id: u32,
66 pub word_id: u32,
67 pub site_id: u32,
68}
69
70impl LocationAddr {
71 pub fn encode(&self) -> u64 {
75 ((self.zone_id as u8 as u64) << 56)
76 | ((self.word_id as u16 as u64) << 40)
77 | ((self.site_id as u16 as u64) << 24)
78 }
79
80 pub fn decode(bits: u64) -> Self {
82 Self {
83 zone_id: ((bits >> 56) & 0xFF) as u32,
84 word_id: ((bits >> 40) & 0xFFFF) as u32,
85 site_id: ((bits >> 24) & 0xFFFF) as u32,
86 }
87 }
88}
89
90impl Serialize for LocationAddr {
91 fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
92 serializer.serialize_u64(self.encode())
93 }
94}
95
96impl<'de> Deserialize<'de> for LocationAddr {
97 fn deserialize<D: Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
98 let bits = u64::deserialize(deserializer)?;
99 Ok(Self::decode(bits))
100 }
101}
102
103#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
113pub struct LaneAddr {
114 pub direction: Direction,
115 pub move_type: MoveType,
116 pub zone_id: u32,
117 pub word_id: u32,
118 pub site_id: u32,
119 pub bus_id: u32,
120}
121
122impl LaneAddr {
123 pub fn encode(&self) -> (u32, u32) {
125 let data0 = ((self.word_id as u16 as u32) << 16) | (self.site_id as u16 as u32);
126 let data1 = ((self.direction as u32) << 31)
127 | ((self.move_type as u32) << 29)
128 | ((self.zone_id as u8 as u32) << 21)
129 | (self.bus_id as u16 as u32);
130 (data0, data1)
131 }
132
133 pub fn encode_u64(&self) -> u64 {
135 let (d0, d1) = self.encode();
136 (d0 as u64) | ((d1 as u64) << 32)
137 }
138
139 pub fn decode(data0: u32, data1: u32) -> Self {
141 let direction = if (data1 >> 31) & 1 == 0 {
142 Direction::Forward
143 } else {
144 Direction::Backward
145 };
146 let mt_bits = (data1 >> 29) & 0x3;
147 let move_type = match mt_bits {
148 0 => MoveType::SiteBus,
149 1 => MoveType::WordBus,
150 2 => MoveType::ZoneBus,
151 _ => panic!("invalid move type bits: {}", mt_bits),
152 };
153 Self {
154 direction,
155 move_type,
156 zone_id: (data1 >> 21) & 0xFF,
157 word_id: (data0 >> 16) & 0xFFFF,
158 site_id: data0 & 0xFFFF,
159 bus_id: data1 & 0xFFFF,
160 }
161 }
162
163 pub fn decode_u64(bits: u64) -> Self {
165 Self::decode(bits as u32, (bits >> 32) as u32)
166 }
167}
168
169#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
176pub struct ZoneAddr {
177 pub zone_id: u32,
178}
179
180impl ZoneAddr {
181 pub fn encode(&self) -> u32 {
183 self.zone_id as u8 as u32
184 }
185
186 pub fn decode(bits: u32) -> Self {
188 Self {
189 zone_id: bits & 0xFF,
190 }
191 }
192}
193
194#[cfg(test)]
195mod tests {
196 use super::*;
197
198 #[test]
199 fn test_move_type_zone_bus() {
200 assert_eq!(MoveType::SiteBus as u8, 0);
201 assert_eq!(MoveType::WordBus as u8, 1);
202 assert_eq!(MoveType::ZoneBus as u8, 2);
203 }
204
205 #[test]
206 fn test_location_addr_64bit_round_trip() {
207 let addr = LocationAddr {
208 zone_id: 5,
209 word_id: 0x1234,
210 site_id: 0x5678,
211 };
212 let bits = addr.encode();
213 assert_eq!(LocationAddr::decode(bits), addr);
214 assert_eq!((bits >> 56) & 0xFF, 5);
215 assert_eq!((bits >> 40) & 0xFFFF, 0x1234);
216 assert_eq!((bits >> 24) & 0xFFFF, 0x5678);
217 assert_eq!(bits & 0xFFFFFF, 0);
218 }
219
220 #[test]
221 fn test_location_addr_zero() {
222 let addr = LocationAddr {
223 zone_id: 0,
224 word_id: 0,
225 site_id: 0,
226 };
227 assert_eq!(addr.encode(), 0u64);
228 assert_eq!(LocationAddr::decode(0), addr);
229 }
230
231 #[test]
232 fn test_lane_addr_round_trip() {
233 let addr = LaneAddr {
234 direction: Direction::Backward,
235 move_type: MoveType::WordBus,
236 zone_id: 0,
237 word_id: 0x1234,
238 site_id: 0x5678,
239 bus_id: 0x9ABC,
240 };
241 let (data0, data1) = addr.encode();
242 assert_eq!(LaneAddr::decode(data0, data1), addr);
243
244 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); }
253
254 #[test]
255 fn test_lane_addr_forward_sitebus() {
256 let addr = LaneAddr {
257 direction: Direction::Forward,
258 move_type: MoveType::SiteBus,
259 zone_id: 0,
260 word_id: 0,
261 site_id: 0,
262 bus_id: 1,
263 };
264 let (data0, data1) = addr.encode();
265 assert_eq!(data0, 0);
266 assert_eq!(data1, 1);
267 assert_eq!(LaneAddr::decode(data0, data1), addr);
268 }
269
270 #[test]
271 fn test_lane_addr_u64_round_trip() {
272 let addr = LaneAddr {
273 direction: Direction::Backward,
274 move_type: MoveType::WordBus,
275 zone_id: 0,
276 word_id: 1,
277 site_id: 0,
278 bus_id: 0,
279 };
280 let packed = addr.encode_u64();
281 assert_eq!(LaneAddr::decode_u64(packed), addr);
282 }
283
284 #[test]
285 fn test_lane_addr_with_zone_id() {
286 let addr = LaneAddr {
287 direction: Direction::Backward,
288 move_type: MoveType::ZoneBus,
289 zone_id: 7,
290 word_id: 0x1234,
291 site_id: 0x5678,
292 bus_id: 0x9ABC,
293 };
294 let (data0, data1) = addr.encode();
295 let decoded = LaneAddr::decode(data0, data1);
296 assert_eq!(decoded, addr);
297 assert_eq!((data0 >> 16) & 0xFFFF, 0x1234);
298 assert_eq!(data0 & 0xFFFF, 0x5678);
299 assert_eq!((data1 >> 31) & 1, 1);
300 assert_eq!((data1 >> 29) & 0x3, 2);
301 assert_eq!((data1 >> 21) & 0xFF, 7);
302 assert_eq!(data1 & 0xFFFF, 0x9ABC);
303 }
304
305 #[test]
306 fn test_zone_addr_round_trip() {
307 let addr = ZoneAddr { zone_id: 42 };
308 let bits = addr.encode();
309 assert_eq!(bits, 42);
310 assert_eq!(ZoneAddr::decode(bits), addr);
311 }
312
313 #[test]
314 fn test_zone_addr_max() {
315 let addr = ZoneAddr { zone_id: 0xFF };
316 let bits = addr.encode();
317 assert_eq!(bits, 0xFF);
318 assert_eq!(ZoneAddr::decode(bits), addr);
319 }
320
321 #[test]
322 fn test_site_ref_newtype() {
323 let s = SiteRef(42);
324 assert_eq!(s.0, 42);
325 let json = serde_json::to_string(&s).unwrap();
326 let deserialized: SiteRef = serde_json::from_str(&json).unwrap();
327 assert_eq!(s, deserialized);
328 }
329
330 #[test]
331 fn test_word_ref_newtype() {
332 let w = WordRef(100);
333 assert_eq!(w.0, 100);
334 let json = serde_json::to_string(&w).unwrap();
335 let deserialized: WordRef = serde_json::from_str(&json).unwrap();
336 assert_eq!(w, deserialized);
337 }
338
339 #[test]
340 fn test_zoned_word_ref() {
341 let zwr = ZonedWordRef {
342 zone_id: 3,
343 word_id: 42,
344 };
345 assert_eq!(zwr.zone_id, 3);
346 assert_eq!(zwr.word_id, 42);
347 let json = serde_json::to_string(&zwr).unwrap();
348 let deserialized: ZonedWordRef = serde_json::from_str(&json).unwrap();
349 assert_eq!(zwr, deserialized);
350 }
351}