1use crate::error::ParseError;
2
3use super::{
4 ConstPackedSizeBytes, DateFormat, FromBytes, KissOfDeath, LeapIndicator, Mode, Packet,
5 PrimarySource, ReferenceIdentifier, ShortFormat, Stratum, TimestampFormat, ToBytes, Version,
6};
7
8impl FromBytes for ShortFormat {
9 fn from_bytes(buf: &[u8]) -> Result<(Self, usize), ParseError> {
10 if buf.len() < Self::PACKED_SIZE_BYTES {
11 return Err(ParseError::BufferTooShort {
12 needed: Self::PACKED_SIZE_BYTES,
13 available: buf.len(),
14 });
15 }
16 let seconds = u16::from_be_bytes([buf[0], buf[1]]);
17 let fraction = u16::from_be_bytes([buf[2], buf[3]]);
18 Ok((ShortFormat { seconds, fraction }, Self::PACKED_SIZE_BYTES))
19 }
20}
21
22impl FromBytes for TimestampFormat {
23 fn from_bytes(buf: &[u8]) -> Result<(Self, usize), ParseError> {
24 if buf.len() < Self::PACKED_SIZE_BYTES {
25 return Err(ParseError::BufferTooShort {
26 needed: Self::PACKED_SIZE_BYTES,
27 available: buf.len(),
28 });
29 }
30 let seconds = u32::from_be_bytes([buf[0], buf[1], buf[2], buf[3]]);
31 let fraction = u32::from_be_bytes([buf[4], buf[5], buf[6], buf[7]]);
32 Ok((
33 TimestampFormat { seconds, fraction },
34 Self::PACKED_SIZE_BYTES,
35 ))
36 }
37}
38
39impl FromBytes for DateFormat {
40 fn from_bytes(buf: &[u8]) -> Result<(Self, usize), ParseError> {
41 if buf.len() < Self::PACKED_SIZE_BYTES {
42 return Err(ParseError::BufferTooShort {
43 needed: Self::PACKED_SIZE_BYTES,
44 available: buf.len(),
45 });
46 }
47 let era_number = i32::from_be_bytes([buf[0], buf[1], buf[2], buf[3]]);
48 let era_offset = u32::from_be_bytes([buf[4], buf[5], buf[6], buf[7]]);
49 let fraction = u64::from_be_bytes([
50 buf[8], buf[9], buf[10], buf[11], buf[12], buf[13], buf[14], buf[15],
51 ]);
52 Ok((
53 DateFormat {
54 era_number,
55 era_offset,
56 fraction,
57 },
58 Self::PACKED_SIZE_BYTES,
59 ))
60 }
61}
62
63impl FromBytes for Stratum {
64 fn from_bytes(buf: &[u8]) -> Result<(Self, usize), ParseError> {
65 if buf.is_empty() {
66 return Err(ParseError::BufferTooShort {
67 needed: 1,
68 available: 0,
69 });
70 }
71 Ok((Stratum(buf[0]), 1))
72 }
73}
74
75impl FromBytes for (LeapIndicator, Version, Mode) {
76 fn from_bytes(buf: &[u8]) -> Result<(Self, usize), ParseError> {
77 if buf.is_empty() {
78 return Err(ParseError::BufferTooShort {
79 needed: 1,
80 available: 0,
81 });
82 }
83 let li_vn_mode = buf[0];
84 let li_u8 = li_vn_mode >> 6;
85 let vn_u8 = (li_vn_mode >> 3) & 0b111;
86 let mode_u8 = li_vn_mode & 0b111;
87 let li = LeapIndicator::try_from(li_u8).map_err(|_| ParseError::InvalidField {
88 field: "leap indicator",
89 value: li_u8 as u32,
90 })?;
91 let vn = Version(vn_u8);
92 let mode = Mode::try_from(mode_u8).map_err(|_| ParseError::InvalidField {
93 field: "association mode",
94 value: mode_u8 as u32,
95 })?;
96 Ok(((li, vn, mode), 1))
97 }
98}
99
100impl ReferenceIdentifier {
101 pub fn from_bytes_with_stratum(bytes: [u8; 4], stratum: Stratum) -> Self {
109 let u = u32::from_be_bytes(bytes);
110 if stratum == Stratum::UNSPECIFIED {
111 match KissOfDeath::try_from(u) {
112 Ok(kod) => ReferenceIdentifier::KissOfDeath(kod),
113 Err(_) => ReferenceIdentifier::Unknown(bytes),
114 }
115 } else if stratum == Stratum::PRIMARY {
116 match PrimarySource::try_from(u) {
117 Ok(src) => ReferenceIdentifier::PrimarySource(src),
118 Err(_) => ReferenceIdentifier::Unknown(bytes),
119 }
120 } else if stratum.is_secondary() {
121 ReferenceIdentifier::SecondaryOrClient(bytes)
122 } else {
123 ReferenceIdentifier::Unknown(bytes)
124 }
125 }
126}
127
128impl FromBytes for Packet {
129 fn from_bytes(buf: &[u8]) -> Result<(Self, usize), ParseError> {
130 if buf.len() < Self::PACKED_SIZE_BYTES {
131 return Err(ParseError::BufferTooShort {
132 needed: Self::PACKED_SIZE_BYTES,
133 available: buf.len(),
134 });
135 }
136
137 let mut offset = 0;
138
139 let ((leap_indicator, version, mode), n) =
140 <(LeapIndicator, Version, Mode)>::from_bytes(&buf[offset..])?;
141 offset += n;
142
143 let (stratum, n) = Stratum::from_bytes(&buf[offset..])?;
144 offset += n;
145
146 let poll = buf[offset] as i8;
147 offset += 1;
148
149 let precision = buf[offset] as i8;
150 offset += 1;
151
152 let (root_delay, n) = ShortFormat::from_bytes(&buf[offset..])?;
153 offset += n;
154
155 let (root_dispersion, n) = ShortFormat::from_bytes(&buf[offset..])?;
156 offset += n;
157
158 let ref_id_bytes = [
159 buf[offset],
160 buf[offset + 1],
161 buf[offset + 2],
162 buf[offset + 3],
163 ];
164 let reference_id = ReferenceIdentifier::from_bytes_with_stratum(ref_id_bytes, stratum);
165 offset += 4;
166
167 let (reference_timestamp, n) = TimestampFormat::from_bytes(&buf[offset..])?;
168 offset += n;
169
170 let (origin_timestamp, n) = TimestampFormat::from_bytes(&buf[offset..])?;
171 offset += n;
172
173 let (receive_timestamp, n) = TimestampFormat::from_bytes(&buf[offset..])?;
174 offset += n;
175
176 let (transmit_timestamp, n) = TimestampFormat::from_bytes(&buf[offset..])?;
177 offset += n;
178
179 Ok((
180 Packet {
181 leap_indicator,
182 version,
183 mode,
184 stratum,
185 poll,
186 precision,
187 root_delay,
188 root_dispersion,
189 reference_id,
190 reference_timestamp,
191 origin_timestamp,
192 receive_timestamp,
193 transmit_timestamp,
194 },
195 offset,
196 ))
197 }
198}
199
200impl ToBytes for ShortFormat {
203 fn to_bytes(&self, buf: &mut [u8]) -> Result<usize, ParseError> {
204 if buf.len() < Self::PACKED_SIZE_BYTES {
205 return Err(ParseError::BufferTooShort {
206 needed: Self::PACKED_SIZE_BYTES,
207 available: buf.len(),
208 });
209 }
210 let s = self.seconds.to_be_bytes();
211 let f = self.fraction.to_be_bytes();
212 buf[0] = s[0];
213 buf[1] = s[1];
214 buf[2] = f[0];
215 buf[3] = f[1];
216 Ok(Self::PACKED_SIZE_BYTES)
217 }
218}
219
220impl ToBytes for TimestampFormat {
221 fn to_bytes(&self, buf: &mut [u8]) -> Result<usize, ParseError> {
222 if buf.len() < Self::PACKED_SIZE_BYTES {
223 return Err(ParseError::BufferTooShort {
224 needed: Self::PACKED_SIZE_BYTES,
225 available: buf.len(),
226 });
227 }
228 let s = self.seconds.to_be_bytes();
229 let f = self.fraction.to_be_bytes();
230 buf[..4].copy_from_slice(&s);
231 buf[4..8].copy_from_slice(&f);
232 Ok(Self::PACKED_SIZE_BYTES)
233 }
234}
235
236impl ToBytes for DateFormat {
237 fn to_bytes(&self, buf: &mut [u8]) -> Result<usize, ParseError> {
238 if buf.len() < Self::PACKED_SIZE_BYTES {
239 return Err(ParseError::BufferTooShort {
240 needed: Self::PACKED_SIZE_BYTES,
241 available: buf.len(),
242 });
243 }
244 buf[..4].copy_from_slice(&self.era_number.to_be_bytes());
245 buf[4..8].copy_from_slice(&self.era_offset.to_be_bytes());
246 buf[8..16].copy_from_slice(&self.fraction.to_be_bytes());
247 Ok(Self::PACKED_SIZE_BYTES)
248 }
249}
250
251impl ToBytes for Stratum {
252 fn to_bytes(&self, buf: &mut [u8]) -> Result<usize, ParseError> {
253 if buf.is_empty() {
254 return Err(ParseError::BufferTooShort {
255 needed: 1,
256 available: 0,
257 });
258 }
259 buf[0] = self.0;
260 Ok(1)
261 }
262}
263
264impl ToBytes for (LeapIndicator, Version, Mode) {
265 fn to_bytes(&self, buf: &mut [u8]) -> Result<usize, ParseError> {
266 if buf.is_empty() {
267 return Err(ParseError::BufferTooShort {
268 needed: 1,
269 available: 0,
270 });
271 }
272 let (li, vn, mode) = *self;
273 let mut li_vn_mode = 0u8;
274 li_vn_mode |= (li as u8) << 6;
275 li_vn_mode |= vn.0 << 3;
276 li_vn_mode |= mode as u8;
277 buf[0] = li_vn_mode;
278 Ok(1)
279 }
280}
281
282impl ToBytes for ReferenceIdentifier {
283 fn to_bytes(&self, buf: &mut [u8]) -> Result<usize, ParseError> {
284 if buf.len() < Self::PACKED_SIZE_BYTES {
285 return Err(ParseError::BufferTooShort {
286 needed: Self::PACKED_SIZE_BYTES,
287 available: buf.len(),
288 });
289 }
290 let bytes = self.as_bytes();
291 buf[..4].copy_from_slice(&bytes);
292 Ok(Self::PACKED_SIZE_BYTES)
293 }
294}
295
296impl ToBytes for Packet {
297 fn to_bytes(&self, buf: &mut [u8]) -> Result<usize, ParseError> {
298 if buf.len() < Self::PACKED_SIZE_BYTES {
299 return Err(ParseError::BufferTooShort {
300 needed: Self::PACKED_SIZE_BYTES,
301 available: buf.len(),
302 });
303 }
304
305 let mut offset = 0;
306
307 let li_vn_mode = (self.leap_indicator, self.version, self.mode);
308 offset += li_vn_mode.to_bytes(&mut buf[offset..])?;
309 offset += self.stratum.to_bytes(&mut buf[offset..])?;
310 buf[offset] = self.poll as u8;
311 offset += 1;
312 buf[offset] = self.precision as u8;
313 offset += 1;
314 offset += self.root_delay.to_bytes(&mut buf[offset..])?;
315 offset += self.root_dispersion.to_bytes(&mut buf[offset..])?;
316 offset += self.reference_id.to_bytes(&mut buf[offset..])?;
317 offset += self.reference_timestamp.to_bytes(&mut buf[offset..])?;
318 offset += self.origin_timestamp.to_bytes(&mut buf[offset..])?;
319 offset += self.receive_timestamp.to_bytes(&mut buf[offset..])?;
320 offset += self.transmit_timestamp.to_bytes(&mut buf[offset..])?;
321
322 Ok(offset)
323 }
324}
325
326#[cfg(all(test, feature = "std"))]
331mod tests {
332 use super::*;
333
334 #[test]
337 fn short_format_roundtrip() {
338 let sf = ShortFormat {
339 seconds: 0x1234,
340 fraction: 0x5678,
341 };
342 let mut buf = [0u8; 4];
343 let written = sf.to_bytes(&mut buf).unwrap();
344 assert_eq!(written, 4);
345 let (decoded, consumed) = ShortFormat::from_bytes(&buf).unwrap();
346 assert_eq!(consumed, 4);
347 assert_eq!(decoded.seconds, sf.seconds);
348 assert_eq!(decoded.fraction, sf.fraction);
349 }
350
351 #[test]
352 fn short_format_edge_values() {
353 for (s, f) in [(0u16, 0u16), (u16::MAX, u16::MAX)] {
354 let sf = ShortFormat {
355 seconds: s,
356 fraction: f,
357 };
358 let mut buf = [0u8; 4];
359 sf.to_bytes(&mut buf).unwrap();
360 let (decoded, _) = ShortFormat::from_bytes(&buf).unwrap();
361 assert_eq!(decoded.seconds, s);
362 assert_eq!(decoded.fraction, f);
363 }
364 }
365
366 #[test]
367 fn short_format_buffer_too_short_read() {
368 let buf = [0u8; 3];
369 let err = ShortFormat::from_bytes(&buf).unwrap_err();
370 assert!(matches!(
371 err,
372 ParseError::BufferTooShort {
373 needed: 4,
374 available: 3
375 }
376 ));
377 }
378
379 #[test]
380 fn short_format_buffer_too_short_write() {
381 let sf = ShortFormat::default();
382 let mut buf = [0u8; 3];
383 let err = sf.to_bytes(&mut buf).unwrap_err();
384 assert!(matches!(err, ParseError::BufferTooShort { .. }));
385 }
386
387 #[test]
390 fn timestamp_format_roundtrip() {
391 let ts = TimestampFormat {
392 seconds: 3_913_056_000,
393 fraction: 0xABCD_1234,
394 };
395 let mut buf = [0u8; 8];
396 let written = ts.to_bytes(&mut buf).unwrap();
397 assert_eq!(written, 8);
398 let (decoded, consumed) = TimestampFormat::from_bytes(&buf).unwrap();
399 assert_eq!(consumed, 8);
400 assert_eq!(decoded.seconds, ts.seconds);
401 assert_eq!(decoded.fraction, ts.fraction);
402 }
403
404 #[test]
405 fn timestamp_format_edge_values() {
406 for (s, f) in [(0u32, 0u32), (u32::MAX, u32::MAX)] {
407 let ts = TimestampFormat {
408 seconds: s,
409 fraction: f,
410 };
411 let mut buf = [0u8; 8];
412 ts.to_bytes(&mut buf).unwrap();
413 let (decoded, _) = TimestampFormat::from_bytes(&buf).unwrap();
414 assert_eq!(decoded.seconds, s);
415 assert_eq!(decoded.fraction, f);
416 }
417 }
418
419 #[test]
420 fn timestamp_format_buffer_too_short() {
421 let buf = [0u8; 7];
422 let err = TimestampFormat::from_bytes(&buf).unwrap_err();
423 assert!(matches!(
424 err,
425 ParseError::BufferTooShort {
426 needed: 8,
427 available: 7
428 }
429 ));
430 }
431
432 #[test]
435 fn date_format_roundtrip() {
436 let df = DateFormat {
437 era_number: -1,
438 era_offset: 0x1234_5678,
439 fraction: 0xDEAD_BEEF_CAFE_BABE,
440 };
441 let mut buf = [0u8; 16];
442 let written = df.to_bytes(&mut buf).unwrap();
443 assert_eq!(written, 16);
444 let (decoded, consumed) = DateFormat::from_bytes(&buf).unwrap();
445 assert_eq!(consumed, 16);
446 assert_eq!(decoded.era_number, df.era_number);
447 assert_eq!(decoded.era_offset, df.era_offset);
448 assert_eq!(decoded.fraction, df.fraction);
449 }
450
451 #[test]
452 fn date_format_buffer_too_short() {
453 let buf = [0u8; 15];
454 let err = DateFormat::from_bytes(&buf).unwrap_err();
455 assert!(matches!(
456 err,
457 ParseError::BufferTooShort {
458 needed: 16,
459 available: 15
460 }
461 ));
462 }
463
464 #[test]
467 fn stratum_roundtrip() {
468 for val in [0u8, 1, 2, 15, 16, 255] {
469 let s = Stratum(val);
470 let mut buf = [0u8; 1];
471 s.to_bytes(&mut buf).unwrap();
472 let (decoded, consumed) = Stratum::from_bytes(&buf).unwrap();
473 assert_eq!(consumed, 1);
474 assert_eq!(decoded.0, val);
475 }
476 }
477
478 #[test]
479 fn stratum_buffer_empty() {
480 let buf: [u8; 0] = [];
481 let err = Stratum::from_bytes(&buf).unwrap_err();
482 assert!(matches!(err, ParseError::BufferTooShort { .. }));
483 }
484
485 #[test]
488 fn li_vn_mode_roundtrip() {
489 let tuple = (LeapIndicator::NoWarning, Version::V4, Mode::Client);
490 let mut buf = [0u8; 1];
491 let written = tuple.to_bytes(&mut buf).unwrap();
492 assert_eq!(written, 1);
493 let (decoded, consumed) = <(LeapIndicator, Version, Mode)>::from_bytes(&buf).unwrap();
494 assert_eq!(consumed, 1);
495 assert_eq!(decoded.0, LeapIndicator::NoWarning);
496 assert_eq!(decoded.1, Version::V4);
497 assert_eq!(decoded.2, Mode::Client);
498 }
499
500 #[test]
501 fn li_vn_mode_byte_encoding() {
502 let tuple = (LeapIndicator::NoWarning, Version::V4, Mode::Client);
504 let mut buf = [0u8; 1];
505 tuple.to_bytes(&mut buf).unwrap();
506 assert_eq!(buf[0], 0x23);
507 }
508
509 #[test]
510 fn li_vn_mode_all_leap_indicators() {
511 for li in [
512 LeapIndicator::NoWarning,
513 LeapIndicator::AddOne,
514 LeapIndicator::SubOne,
515 LeapIndicator::Unknown,
516 ] {
517 let mut buf = [0u8; 1];
518 (li, Version::V4, Mode::Server).to_bytes(&mut buf).unwrap();
519 let (decoded, _) = <(LeapIndicator, Version, Mode)>::from_bytes(&buf).unwrap();
520 assert_eq!(decoded.0, li);
521 }
522 }
523
524 #[test]
525 fn li_vn_mode_buffer_empty() {
526 let buf: [u8; 0] = [];
527 let err = <(LeapIndicator, Version, Mode)>::from_bytes(&buf).unwrap_err();
528 assert!(matches!(err, ParseError::BufferTooShort { .. }));
529 }
530
531 #[test]
534 fn reference_id_to_bytes_primary() {
535 let ref_id = ReferenceIdentifier::PrimarySource(PrimarySource::Gps);
536 let mut buf = [0u8; 4];
537 let written = ref_id.to_bytes(&mut buf).unwrap();
538 assert_eq!(written, 4);
539 }
540
541 #[test]
542 fn reference_id_to_bytes_secondary() {
543 let ref_id = ReferenceIdentifier::SecondaryOrClient([192, 168, 1, 1]);
544 let mut buf = [0u8; 4];
545 ref_id.to_bytes(&mut buf).unwrap();
546 assert_eq!(buf, [192, 168, 1, 1]);
547 }
548
549 #[test]
550 fn reference_id_buffer_too_short() {
551 let ref_id = ReferenceIdentifier::PrimarySource(PrimarySource::Gps);
552 let mut buf = [0u8; 3];
553 let err = ref_id.to_bytes(&mut buf).unwrap_err();
554 assert!(matches!(err, ParseError::BufferTooShort { .. }));
555 }
556
557 #[test]
558 fn reference_id_from_bytes_with_stratum_kod() {
559 let kod = ReferenceIdentifier::KissOfDeath(KissOfDeath::Deny);
560 let bytes = kod.as_bytes();
561 let decoded = ReferenceIdentifier::from_bytes_with_stratum(bytes, Stratum::UNSPECIFIED);
562 assert!(matches!(
563 decoded,
564 ReferenceIdentifier::KissOfDeath(KissOfDeath::Deny)
565 ));
566 }
567
568 #[test]
569 fn reference_id_from_bytes_with_stratum_primary() {
570 let src = ReferenceIdentifier::PrimarySource(PrimarySource::Gps);
571 let bytes = src.as_bytes();
572 let decoded = ReferenceIdentifier::from_bytes_with_stratum(bytes, Stratum::PRIMARY);
573 assert!(matches!(
574 decoded,
575 ReferenceIdentifier::PrimarySource(PrimarySource::Gps)
576 ));
577 }
578
579 #[test]
580 fn reference_id_from_bytes_with_stratum_secondary() {
581 let bytes = [10, 0, 0, 1];
582 let decoded = ReferenceIdentifier::from_bytes_with_stratum(bytes, Stratum(2));
583 assert!(matches!(
584 decoded,
585 ReferenceIdentifier::SecondaryOrClient([10, 0, 0, 1])
586 ));
587 }
588
589 #[test]
590 fn reference_id_from_bytes_with_stratum_unknown() {
591 let bytes = [0xFF, 0xFE, 0xFD, 0xFC];
592 let decoded = ReferenceIdentifier::from_bytes_with_stratum(bytes, Stratum(16));
593 assert!(matches!(decoded, ReferenceIdentifier::Unknown(_)));
594 }
595
596 fn make_test_packet() -> Packet {
599 Packet {
600 leap_indicator: LeapIndicator::NoWarning,
601 version: Version::V4,
602 mode: Mode::Client,
603 stratum: Stratum::UNSPECIFIED,
604 poll: 6,
605 precision: -20,
606 root_delay: ShortFormat {
607 seconds: 1,
608 fraction: 0x8000,
609 },
610 root_dispersion: ShortFormat {
611 seconds: 0,
612 fraction: 0x4000,
613 },
614 reference_id: ReferenceIdentifier::default(),
615 reference_timestamp: TimestampFormat {
616 seconds: 3_913_056_000,
617 fraction: 0,
618 },
619 origin_timestamp: TimestampFormat::default(),
620 receive_timestamp: TimestampFormat::default(),
621 transmit_timestamp: TimestampFormat {
622 seconds: 3_913_056_001,
623 fraction: 0x1234_5678,
624 },
625 }
626 }
627
628 #[test]
629 fn packet_roundtrip() {
630 let pkt = make_test_packet();
631 let mut buf = [0u8; 48];
632 let written = pkt.to_bytes(&mut buf).unwrap();
633 assert_eq!(written, 48);
634 let (decoded, consumed) = Packet::from_bytes(&buf).unwrap();
635 assert_eq!(consumed, 48);
636 assert_eq!(decoded.leap_indicator, pkt.leap_indicator);
637 assert_eq!(decoded.version, pkt.version);
638 assert_eq!(decoded.mode, pkt.mode);
639 assert_eq!(decoded.stratum, pkt.stratum);
640 assert_eq!(decoded.poll, pkt.poll);
641 assert_eq!(decoded.precision, pkt.precision);
642 assert_eq!(decoded.root_delay, pkt.root_delay);
643 assert_eq!(decoded.root_dispersion, pkt.root_dispersion);
644 assert_eq!(decoded.reference_timestamp, pkt.reference_timestamp);
645 assert_eq!(decoded.origin_timestamp, pkt.origin_timestamp);
646 assert_eq!(decoded.receive_timestamp, pkt.receive_timestamp);
647 assert_eq!(decoded.transmit_timestamp, pkt.transmit_timestamp);
648 }
649
650 #[test]
651 fn packet_size_constant() {
652 assert_eq!(Packet::PACKED_SIZE_BYTES, 48);
653 }
654
655 #[test]
656 fn packet_from_bytes_too_short() {
657 let buf = [0u8; 47];
658 let err = Packet::from_bytes(&buf).unwrap_err();
659 assert!(matches!(
660 err,
661 ParseError::BufferTooShort {
662 needed: 48,
663 available: 47
664 }
665 ));
666 }
667
668 #[test]
669 fn packet_to_bytes_too_short() {
670 let pkt = make_test_packet();
671 let mut buf = [0u8; 47];
672 let err = pkt.to_bytes(&mut buf).unwrap_err();
673 assert!(matches!(err, ParseError::BufferTooShort { .. }));
674 }
675
676 #[test]
677 fn packet_stratum1_gps_reference() {
678 let pkt = Packet {
679 stratum: Stratum::PRIMARY,
680 reference_id: ReferenceIdentifier::PrimarySource(PrimarySource::Gps),
681 ..make_test_packet()
682 };
683 let mut buf = [0u8; 48];
684 pkt.to_bytes(&mut buf).unwrap();
685 let (decoded, _) = Packet::from_bytes(&buf).unwrap();
686 assert!(matches!(
687 decoded.reference_id,
688 ReferenceIdentifier::PrimarySource(PrimarySource::Gps)
689 ));
690 }
691
692 #[test]
693 fn packet_stratum0_kod() {
694 let pkt = Packet {
695 stratum: Stratum::UNSPECIFIED,
696 reference_id: ReferenceIdentifier::KissOfDeath(KissOfDeath::Deny),
697 ..make_test_packet()
698 };
699 let mut buf = [0u8; 48];
700 pkt.to_bytes(&mut buf).unwrap();
701 let (decoded, _) = Packet::from_bytes(&buf).unwrap();
702 assert!(matches!(
703 decoded.reference_id,
704 ReferenceIdentifier::KissOfDeath(KissOfDeath::Deny)
705 ));
706 }
707
708 #[test]
709 fn packet_stratum2_secondary() {
710 let pkt = Packet {
711 stratum: Stratum(2),
712 reference_id: ReferenceIdentifier::SecondaryOrClient([10, 0, 0, 1]),
713 ..make_test_packet()
714 };
715 let mut buf = [0u8; 48];
716 pkt.to_bytes(&mut buf).unwrap();
717 let (decoded, _) = Packet::from_bytes(&buf).unwrap();
718 assert!(matches!(
719 decoded.reference_id,
720 ReferenceIdentifier::SecondaryOrClient([10, 0, 0, 1])
721 ));
722 }
723
724 #[test]
725 fn packet_negative_poll_precision() {
726 let pkt = Packet {
727 poll: -6,
728 precision: -32,
729 ..make_test_packet()
730 };
731 let mut buf = [0u8; 48];
732 pkt.to_bytes(&mut buf).unwrap();
733 let (decoded, _) = Packet::from_bytes(&buf).unwrap();
734 assert_eq!(decoded.poll, -6);
735 assert_eq!(decoded.precision, -32);
736 }
737
738 #[test]
739 fn packet_extra_bytes_ignored() {
740 let pkt = make_test_packet();
741 let mut buf = [0u8; 64];
742 pkt.to_bytes(&mut buf).unwrap();
743 let (decoded, consumed) = Packet::from_bytes(&buf).unwrap();
744 assert_eq!(consumed, 48);
745 assert_eq!(decoded.version, pkt.version);
746 }
747
748 #[test]
751 fn bytes_and_io_produce_same_output() {
752 use crate::protocol::WriteBytes;
755
756 let pkt = make_test_packet();
757
758 let mut buf_bytes = [0u8; 48];
760 pkt.to_bytes(&mut buf_bytes).unwrap();
761
762 let mut io_bytes = Vec::new();
764 io_bytes.write_bytes(pkt).unwrap();
765
766 assert_eq!(&buf_bytes[..], &io_bytes[..]);
767 }
768}