1use crate::UID;
11
12pub const HEADER_SIZE: usize = 24;
14
15pub const MAX_PAYLOAD_SIZE: usize = 1024 * 1024;
19
20#[derive(Debug, Clone, thiserror::Error)]
22pub enum WireError {
23 #[error("insufficient data: need {needed} bytes, have {have}")]
25 InsufficientData {
26 needed: usize,
28 have: usize,
30 },
31
32 #[error("checksum mismatch: expected {expected:#010x}, got {actual:#010x}")]
34 ChecksumMismatch {
35 expected: u32,
37 actual: u32,
39 },
40
41 #[error("packet too large: {size} bytes (max {MAX_PAYLOAD_SIZE})")]
43 PacketTooLarge {
44 size: usize,
46 },
47
48 #[error("invalid packet length: {length}")]
50 InvalidLength {
51 length: u32,
53 },
54}
55
56#[derive(Debug, Clone, Copy, PartialEq, Eq)]
60pub struct PacketHeader {
61 pub length: u32,
63 pub checksum: u32,
65 pub token: UID,
67}
68
69impl PacketHeader {
70 pub fn serialize_into(&self, buf: &mut [u8]) {
76 debug_assert!(buf.len() >= HEADER_SIZE);
77 buf[0..4].copy_from_slice(&self.length.to_le_bytes());
78 buf[4..8].copy_from_slice(&self.checksum.to_le_bytes());
79 buf[8..16].copy_from_slice(&self.token.first.to_le_bytes());
80 buf[16..24].copy_from_slice(&self.token.second.to_le_bytes());
81 }
82
83 pub fn deserialize(buf: &[u8]) -> Result<Self, WireError> {
89 if buf.len() < HEADER_SIZE {
90 return Err(WireError::InsufficientData {
91 needed: HEADER_SIZE,
92 have: buf.len(),
93 });
94 }
95
96 let length = u32::from_le_bytes([buf[0], buf[1], buf[2], buf[3]]);
97 let checksum = u32::from_le_bytes([buf[4], buf[5], buf[6], buf[7]]);
98 let first = u64::from_le_bytes([
99 buf[8], buf[9], buf[10], buf[11], buf[12], buf[13], buf[14], buf[15],
100 ]);
101 let second = u64::from_le_bytes([
102 buf[16], buf[17], buf[18], buf[19], buf[20], buf[21], buf[22], buf[23],
103 ]);
104
105 Ok(Self {
106 length,
107 checksum,
108 token: UID::new(first, second),
109 })
110 }
111}
112
113fn compute_checksum(token: UID, payload: &[u8]) -> u32 {
115 let mut data = Vec::with_capacity(16 + payload.len());
116 data.extend_from_slice(&token.first.to_le_bytes());
117 data.extend_from_slice(&token.second.to_le_bytes());
118 data.extend_from_slice(payload);
119 crc32c::crc32c(&data)
120}
121
122pub fn serialize_packet(token: UID, payload: &[u8]) -> Result<Vec<u8>, WireError> {
145 if payload.len() > MAX_PAYLOAD_SIZE {
146 return Err(WireError::PacketTooLarge {
147 size: payload.len(),
148 });
149 }
150
151 let total_length = HEADER_SIZE + payload.len();
152 let mut data = vec![0u8; total_length];
153
154 let checksum = compute_checksum(token, payload);
155
156 let header = PacketHeader {
157 length: total_length as u32,
158 checksum,
159 token,
160 };
161
162 header.serialize_into(&mut data[..HEADER_SIZE]);
163 data[HEADER_SIZE..].copy_from_slice(payload);
164
165 Ok(data)
166}
167
168pub fn deserialize_packet(data: &[u8]) -> Result<(UID, Vec<u8>), WireError> {
188 let header = PacketHeader::deserialize(data)?;
189
190 if header.length < HEADER_SIZE as u32 {
192 return Err(WireError::InvalidLength {
193 length: header.length,
194 });
195 }
196
197 let expected_len = header.length as usize;
198 if data.len() < expected_len {
199 return Err(WireError::InsufficientData {
200 needed: expected_len,
201 have: data.len(),
202 });
203 }
204
205 let payload = &data[HEADER_SIZE..expected_len];
206
207 let computed = compute_checksum(header.token, payload);
209 if computed != header.checksum {
210 return Err(WireError::ChecksumMismatch {
211 expected: header.checksum,
212 actual: computed,
213 });
214 }
215
216 Ok((header.token, payload.to_vec()))
217}
218
219pub fn try_deserialize_packet(data: &[u8]) -> Result<Option<(UID, Vec<u8>, usize)>, WireError> {
245 if data.len() < HEADER_SIZE {
246 return Ok(None); }
248
249 let header = PacketHeader::deserialize(data)?;
250
251 if header.length < HEADER_SIZE as u32 {
252 return Err(WireError::InvalidLength {
253 length: header.length,
254 });
255 }
256
257 let expected_len = header.length as usize;
258 if data.len() < expected_len {
259 return Ok(None); }
261
262 let payload = &data[HEADER_SIZE..expected_len];
263
264 let computed = compute_checksum(header.token, payload);
266 if computed != header.checksum {
267 return Err(WireError::ChecksumMismatch {
268 expected: header.checksum,
269 actual: computed,
270 });
271 }
272
273 Ok(Some((header.token, payload.to_vec(), expected_len)))
274}
275
276#[cfg(test)]
277mod tests {
278 use super::*;
279 use crate::WellKnownToken;
280
281 #[test]
282 fn test_serialize_deserialize_roundtrip() {
283 let token = UID::new(0x123456789ABCDEF0, 0xFEDCBA9876543210);
284 let payload = b"hello world";
285
286 let packet = serialize_packet(token, payload).expect("serialize");
287 let (recv_token, recv_payload) = deserialize_packet(&packet).expect("deserialize");
288
289 assert_eq!(token, recv_token);
290 assert_eq!(payload.as_slice(), recv_payload.as_slice());
291 }
292
293 #[test]
294 fn test_checksum_validation() {
295 let token = UID::new(1, 2);
296 let packet = serialize_packet(token, b"test").expect("serialize");
297
298 let mut corrupted = packet.clone();
300 corrupted[HEADER_SIZE] ^= 0xFF;
301
302 let result = deserialize_packet(&corrupted);
303 assert!(matches!(result, Err(WireError::ChecksumMismatch { .. })));
304 }
305
306 #[test]
307 fn test_checksum_header_corruption() {
308 let token = UID::new(1, 2);
309 let packet = serialize_packet(token, b"test").expect("serialize");
310
311 let mut corrupted = packet.clone();
313 corrupted[10] ^= 0xFF;
314
315 let result = deserialize_packet(&corrupted);
316 assert!(matches!(result, Err(WireError::ChecksumMismatch { .. })));
317 }
318
319 #[test]
320 fn test_well_known_token() {
321 let token = UID::well_known(WellKnownToken::Ping as u32);
322 assert!(token.is_well_known());
323 assert_eq!(token.first, u64::MAX);
324 assert_eq!(token.second, 1);
325
326 let packet = serialize_packet(token, b"ping").expect("serialize");
328 let (recv_token, _) = deserialize_packet(&packet).expect("deserialize");
329 assert_eq!(token, recv_token);
330 }
331
332 #[test]
333 fn test_insufficient_data_header() {
334 let result = deserialize_packet(&[0u8; 10]);
335 assert!(matches!(
336 result,
337 Err(WireError::InsufficientData {
338 needed: HEADER_SIZE,
339 have: 10
340 })
341 ));
342 }
343
344 #[test]
345 fn test_insufficient_data_payload() {
346 let token = UID::new(1, 2);
347 let packet = serialize_packet(token, b"test data that is longer").expect("serialize");
348
349 let partial = &packet[..HEADER_SIZE + 5];
351 let result = deserialize_packet(partial);
352 assert!(matches!(result, Err(WireError::InsufficientData { .. })));
353 }
354
355 #[test]
356 fn test_try_deserialize_partial_header() {
357 let token = UID::new(1, 2);
358 let packet = serialize_packet(token, b"test data").expect("serialize");
359
360 let result = try_deserialize_packet(&packet[..10]);
362 assert!(matches!(result, Ok(None)));
363 }
364
365 #[test]
366 fn test_try_deserialize_partial_payload() {
367 let token = UID::new(1, 2);
368 let packet = serialize_packet(token, b"test data").expect("serialize");
369
370 let result = try_deserialize_packet(&packet[..HEADER_SIZE + 2]);
372 assert!(matches!(result, Ok(None)));
373 }
374
375 #[test]
376 fn test_try_deserialize_complete() {
377 let token = UID::new(1, 2);
378 let packet = serialize_packet(token, b"test data").expect("serialize");
379
380 let result = try_deserialize_packet(&packet).expect("deserialize");
382 assert!(result.is_some());
383
384 let (recv_token, recv_payload, consumed) = result.expect("has data");
385 assert_eq!(token, recv_token);
386 assert_eq!(b"test data".as_slice(), recv_payload.as_slice());
387 assert_eq!(consumed, packet.len());
388 }
389
390 #[test]
391 fn test_try_deserialize_with_extra_data() {
392 let token = UID::new(1, 2);
393 let packet = serialize_packet(token, b"test").expect("serialize");
394
395 let mut extended = packet.clone();
397 extended.extend_from_slice(b"extra garbage");
398
399 let result = try_deserialize_packet(&extended).expect("deserialize");
400 let (recv_token, recv_payload, consumed) = result.expect("has data");
401
402 assert_eq!(token, recv_token);
403 assert_eq!(b"test".as_slice(), recv_payload.as_slice());
404 assert_eq!(consumed, packet.len()); }
406
407 #[test]
408 fn test_adjusted_uid() {
409 let base = UID::new(0x1000, 0x2000);
410 let adj1 = base.adjusted(1);
411 let adj2 = base.adjusted(2);
412
413 assert_ne!(base, adj1);
415 assert_ne!(adj1, adj2);
416 assert_ne!(base, adj2);
417
418 for (i, uid) in [base, adj1, adj2].iter().enumerate() {
420 let packet = serialize_packet(*uid, format!("msg{}", i).as_bytes()).expect("serialize");
421 let (recv_token, _) = deserialize_packet(&packet).expect("deserialize");
422 assert_eq!(*uid, recv_token);
423 }
424 }
425
426 #[test]
427 fn test_empty_payload() {
428 let token = UID::new(42, 43);
429 let packet = serialize_packet(token, &[]).expect("serialize");
430
431 assert_eq!(packet.len(), HEADER_SIZE);
432
433 let (recv_token, recv_payload) = deserialize_packet(&packet).expect("deserialize");
434 assert_eq!(token, recv_token);
435 assert!(recv_payload.is_empty());
436 }
437
438 #[test]
439 fn test_packet_too_large() {
440 let token = UID::new(1, 1);
441 let large_payload = vec![0u8; MAX_PAYLOAD_SIZE + 1];
442
443 let result = serialize_packet(token, &large_payload);
444 assert!(matches!(result, Err(WireError::PacketTooLarge { .. })));
445 }
446
447 #[test]
448 fn test_max_size_payload() {
449 let token = UID::new(1, 1);
450 let max_payload = vec![0xAB; MAX_PAYLOAD_SIZE];
451
452 let packet = serialize_packet(token, &max_payload).expect("serialize");
453 let (recv_token, recv_payload) = deserialize_packet(&packet).expect("deserialize");
454
455 assert_eq!(token, recv_token);
456 assert_eq!(max_payload, recv_payload);
457 }
458
459 #[test]
460 fn test_invalid_length_too_small() {
461 let mut bad_packet = vec![0u8; HEADER_SIZE];
463 bad_packet[0..4].copy_from_slice(&10u32.to_le_bytes()); let result = deserialize_packet(&bad_packet);
466 assert!(matches!(
467 result,
468 Err(WireError::InvalidLength { length: 10 })
469 ));
470 }
471
472 #[test]
473 fn test_header_serialization() {
474 let header = PacketHeader {
475 length: 100,
476 checksum: 0xDEADBEEF,
477 token: UID::new(0x1234567890ABCDEF, 0xFEDCBA0987654321),
478 };
479
480 let mut buf = [0u8; HEADER_SIZE];
481 header.serialize_into(&mut buf);
482
483 let deserialized = PacketHeader::deserialize(&buf).expect("deserialize");
484 assert_eq!(header, deserialized);
485 }
486
487 #[test]
488 fn test_packet_structure() {
489 let token = UID::new(0x1111111111111111, 0x2222222222222222);
490 let payload = b"test";
491
492 let packet = serialize_packet(token, payload).expect("serialize");
493
494 assert_eq!(packet.len(), HEADER_SIZE + payload.len());
496
497 let length = u32::from_le_bytes([packet[0], packet[1], packet[2], packet[3]]);
499 assert_eq!(length as usize, packet.len());
500
501 let first = u64::from_le_bytes(packet[8..16].try_into().expect("slice"));
503 let second = u64::from_le_bytes(packet[16..24].try_into().expect("slice"));
504 assert_eq!(first, token.first);
505 assert_eq!(second, token.second);
506
507 assert_eq!(&packet[HEADER_SIZE..], payload.as_slice());
509 }
510}