1#[cfg(feature = "std")]
10use byteorder::{BE, ReadBytesExt, WriteBytesExt};
11use core::fmt;
12#[cfg(feature = "std")]
13use std::io;
14
15use crate::error::ParseError;
16
17pub const PORT: u8 = 123;
19
20pub const TOLERANCE: f64 = 15e-6;
22
23pub const MINPOLL: u8 = 4;
25
26pub const MAXPOLL: u8 = 17;
28
29pub const MAXDISP: f64 = 16.0;
31
32pub const MINDISP: f64 = 0.005;
34
35pub const MAXDIST: u8 = 1;
37
38pub const MAXSTRAT: u8 = 16;
40
41#[cfg(feature = "std")]
46pub trait WriteBytes {
47 fn write_bytes<P: WriteToBytes>(&mut self, protocol: P) -> io::Result<()>;
49}
50
51#[cfg(feature = "std")]
56pub trait ReadBytes {
57 fn read_bytes<P: ReadFromBytes>(&mut self) -> io::Result<P>;
59}
60
61#[cfg(feature = "std")]
64pub trait WriteToBytes {
65 fn write_to_bytes<W: WriteBytesExt>(&self, writer: W) -> io::Result<()>;
67}
68
69#[cfg(feature = "std")]
72pub trait ReadFromBytes: Sized {
73 fn read_from_bytes<R: ReadBytesExt>(reader: R) -> io::Result<Self>;
75}
76
77pub trait ConstPackedSizeBytes {
79 const PACKED_SIZE_BYTES: usize;
81}
82
83pub trait FromBytes: Sized {
90 fn from_bytes(buf: &[u8]) -> Result<(Self, usize), ParseError>;
93}
94
95pub trait ToBytes {
100 fn to_bytes(&self, buf: &mut [u8]) -> Result<usize, ParseError>;
103}
104
105#[repr(C)]
119#[derive(Clone, Copy, Debug, Default, Eq, Hash, Ord, PartialEq, PartialOrd)]
120pub struct ShortFormat {
121 pub seconds: u16,
123 pub fraction: u16,
125}
126
127#[repr(C)]
145#[derive(Clone, Copy, Debug, Default, Eq, Hash, Ord, PartialEq, PartialOrd)]
146pub struct TimestampFormat {
147 pub seconds: u32,
149 pub fraction: u32,
151}
152
153#[repr(C)]
174#[derive(Clone, Copy, Debug, Default, Eq, Hash, Ord, PartialEq, PartialOrd)]
175pub struct DateFormat {
176 pub era_number: i32,
178 pub era_offset: u32,
180 pub fraction: u64,
182}
183
184#[repr(u8)]
192#[derive(Copy, Clone, Debug, Default, Eq, Hash, PartialEq)]
193pub enum LeapIndicator {
194 #[default]
196 NoWarning = 0,
197 AddOne = 1,
199 SubOne = 2,
201 Unknown = 3,
203}
204
205impl TryFrom<u8> for LeapIndicator {
206 type Error = ();
207
208 fn try_from(value: u8) -> Result<Self, Self::Error> {
209 match value {
210 0 => Ok(LeapIndicator::NoWarning),
211 1 => Ok(LeapIndicator::AddOne),
212 2 => Ok(LeapIndicator::SubOne),
213 3 => Ok(LeapIndicator::Unknown),
214 _ => Err(()),
215 }
216 }
217}
218
219#[derive(Copy, Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
226pub struct Version(u8);
227
228#[repr(u8)]
235#[derive(Copy, Clone, Debug, Eq, Hash, PartialEq)]
236pub enum Mode {
237 Reserved = 0,
239 SymmetricActive = 1,
241 SymmetricPassive = 2,
243 Client = 3,
245 Server = 4,
247 Broadcast = 5,
249 NtpControlMessage = 6,
251 ReservedForPrivateUse = 7,
253}
254
255impl TryFrom<u8> for Mode {
256 type Error = ();
257
258 fn try_from(value: u8) -> Result<Self, Self::Error> {
259 match value {
260 0 => Ok(Mode::Reserved),
261 1 => Ok(Mode::SymmetricActive),
262 2 => Ok(Mode::SymmetricPassive),
263 3 => Ok(Mode::Client),
264 4 => Ok(Mode::Server),
265 5 => Ok(Mode::Broadcast),
266 6 => Ok(Mode::NtpControlMessage),
267 7 => Ok(Mode::ReservedForPrivateUse),
268 _ => Err(()),
269 }
270 }
271}
272
273#[derive(Copy, Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
292pub struct Stratum(pub u8);
293
294#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
307pub enum ReferenceIdentifier {
308 PrimarySource(PrimarySource),
310 SecondaryOrClient([u8; 4]),
320 KissOfDeath(KissOfDeath),
322 Unknown([u8; 4]),
328}
329
330macro_rules! code_to_u32 {
332 ($w:expr) => {
333 (($w[3] as u32) << 0)
334 | (($w[2] as u32) << 8)
335 | (($w[1] as u32) << 16)
336 | (($w[0] as u32) << 24)
337 | ((*$w as [u8; 4])[0] as u32 * 0)
338 };
339}
340
341#[repr(u32)]
351#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
352#[allow(missing_docs)]
353pub enum PrimarySource {
354 Goes = code_to_u32!(b"GOES"),
356 Gps = code_to_u32!(b"GPS\0"),
358 Cdma = code_to_u32!(b"CDMA"),
360 Gal = code_to_u32!(b"GAL\0"),
361 Pps = code_to_u32!(b"PPS\0"),
362 Irig = code_to_u32!(b"IRIG"),
363 Wwvb = code_to_u32!(b"WWVB"),
364 Dcf = code_to_u32!(b"DCF\0"),
365 Hgb = code_to_u32!(b"HGB\0"),
366 Msf = code_to_u32!(b"MSF\0"),
367 Jjy = code_to_u32!(b"JJY\0"),
368 Lorc = code_to_u32!(b"LORC"),
369 Tdf = code_to_u32!(b"TDF\0"),
370 Chu = code_to_u32!(b"CHU\0"),
371 Wwv = code_to_u32!(b"WWV\0"),
372 Wwvh = code_to_u32!(b"WWVH"),
373 Nist = code_to_u32!(b"NIST"),
374 Acts = code_to_u32!(b"ACTS"),
375 Usno = code_to_u32!(b"USNO"),
376 Ptb = code_to_u32!(b"PTB\0"),
377 Goog = code_to_u32!(b"GOOG"),
378 Locl = code_to_u32!(b"LOCL"),
379 Cesm = code_to_u32!(b"CESM"),
380 Rbdm = code_to_u32!(b"RBDM"),
381 Omeg = code_to_u32!(b"OMEG"),
382 Dcn = code_to_u32!(b"DCN\0"),
383 Tsp = code_to_u32!(b"TSP\0"),
384 Dts = code_to_u32!(b"DTS\0"),
385 Atom = code_to_u32!(b"ATOM"),
386 Vlf = code_to_u32!(b"VLF\0"),
387 Opps = code_to_u32!(b"OPPS"),
388 Free = code_to_u32!(b"FREE"),
389 Init = code_to_u32!(b"INIT"),
390 Null = 0,
391}
392
393impl TryFrom<u32> for PrimarySource {
394 type Error = ();
395
396 fn try_from(value: u32) -> Result<Self, Self::Error> {
397 match value {
398 v if v == code_to_u32!(b"GOES") => Ok(PrimarySource::Goes),
399 v if v == code_to_u32!(b"GPS\0") => Ok(PrimarySource::Gps),
400 v if v == code_to_u32!(b"CDMA") => Ok(PrimarySource::Cdma),
401 v if v == code_to_u32!(b"GAL\0") => Ok(PrimarySource::Gal),
402 v if v == code_to_u32!(b"PPS\0") => Ok(PrimarySource::Pps),
403 v if v == code_to_u32!(b"IRIG") => Ok(PrimarySource::Irig),
404 v if v == code_to_u32!(b"WWVB") => Ok(PrimarySource::Wwvb),
405 v if v == code_to_u32!(b"DCF\0") => Ok(PrimarySource::Dcf),
406 v if v == code_to_u32!(b"HGB\0") => Ok(PrimarySource::Hgb),
407 v if v == code_to_u32!(b"MSF\0") => Ok(PrimarySource::Msf),
408 v if v == code_to_u32!(b"JJY\0") => Ok(PrimarySource::Jjy),
409 v if v == code_to_u32!(b"LORC") => Ok(PrimarySource::Lorc),
410 v if v == code_to_u32!(b"TDF\0") => Ok(PrimarySource::Tdf),
411 v if v == code_to_u32!(b"CHU\0") => Ok(PrimarySource::Chu),
412 v if v == code_to_u32!(b"WWV\0") => Ok(PrimarySource::Wwv),
413 v if v == code_to_u32!(b"WWVH") => Ok(PrimarySource::Wwvh),
414 v if v == code_to_u32!(b"NIST") => Ok(PrimarySource::Nist),
415 v if v == code_to_u32!(b"ACTS") => Ok(PrimarySource::Acts),
416 v if v == code_to_u32!(b"USNO") => Ok(PrimarySource::Usno),
417 v if v == code_to_u32!(b"PTB\0") => Ok(PrimarySource::Ptb),
418 v if v == code_to_u32!(b"GOOG") => Ok(PrimarySource::Goog),
419 v if v == code_to_u32!(b"LOCL") => Ok(PrimarySource::Locl),
420 v if v == code_to_u32!(b"CESM") => Ok(PrimarySource::Cesm),
421 v if v == code_to_u32!(b"RBDM") => Ok(PrimarySource::Rbdm),
422 v if v == code_to_u32!(b"OMEG") => Ok(PrimarySource::Omeg),
423 v if v == code_to_u32!(b"DCN\0") => Ok(PrimarySource::Dcn),
424 v if v == code_to_u32!(b"TSP\0") => Ok(PrimarySource::Tsp),
425 v if v == code_to_u32!(b"DTS\0") => Ok(PrimarySource::Dts),
426 v if v == code_to_u32!(b"ATOM") => Ok(PrimarySource::Atom),
427 v if v == code_to_u32!(b"VLF\0") => Ok(PrimarySource::Vlf),
428 v if v == code_to_u32!(b"OPPS") => Ok(PrimarySource::Opps),
429 v if v == code_to_u32!(b"FREE") => Ok(PrimarySource::Free),
430 v if v == code_to_u32!(b"INIT") => Ok(PrimarySource::Init),
431 0 => Ok(PrimarySource::Null),
432 _ => Err(()),
433 }
434 }
435}
436
437#[repr(u32)]
451#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
452pub enum KissOfDeath {
453 Deny = code_to_u32!(b"DENY"),
455 Rstr = code_to_u32!(b"RSTR"),
457 Rate = code_to_u32!(b"RATE"),
460}
461
462impl TryFrom<u32> for KissOfDeath {
463 type Error = ();
464
465 fn try_from(value: u32) -> Result<Self, Self::Error> {
466 match value {
467 v if v == code_to_u32!(b"DENY") => Ok(KissOfDeath::Deny),
468 v if v == code_to_u32!(b"RSTR") => Ok(KissOfDeath::Rstr),
469 v if v == code_to_u32!(b"RATE") => Ok(KissOfDeath::Rate),
470 _ => Err(()),
471 }
472 }
473}
474
475#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
560pub struct Packet {
561 pub leap_indicator: LeapIndicator,
563 pub version: Version,
565 pub mode: Mode,
567 pub stratum: Stratum,
569 pub poll: i8,
573 pub precision: i8,
578 pub root_delay: ShortFormat,
580 pub root_dispersion: ShortFormat,
582 pub reference_id: ReferenceIdentifier,
584 pub reference_timestamp: TimestampFormat,
586 pub origin_timestamp: TimestampFormat,
588 pub receive_timestamp: TimestampFormat,
590 pub transmit_timestamp: TimestampFormat,
592}
593
594pub type PacketByte1 = (LeapIndicator, Version, Mode);
596
597impl ReferenceIdentifier {
600 pub fn as_bytes(&self) -> [u8; 4] {
602 match *self {
603 ReferenceIdentifier::PrimarySource(src) => src.bytes(),
604 ReferenceIdentifier::SecondaryOrClient(arr) => arr,
605 ReferenceIdentifier::KissOfDeath(kod) => be_u32_to_bytes(kod as u32),
606 ReferenceIdentifier::Unknown(arr) => arr,
607 }
608 }
609
610 pub fn is_kiss_of_death(&self) -> bool {
612 matches!(self, ReferenceIdentifier::KissOfDeath(_))
613 }
614}
615
616impl PrimarySource {
617 pub fn bytes(&self) -> [u8; 4] {
619 be_u32_to_bytes(*self as u32)
620 }
621}
622
623impl Version {
624 pub const V1: Self = Version(1);
626 pub const V2: Self = Version(2);
628 pub const V3: Self = Version(3);
630 pub const V4: Self = Version(4);
632
633 pub fn is_known(&self) -> bool {
635 self.0 >= 1 && self.0 <= 4
636 }
637}
638
639impl Stratum {
640 pub const UNSPECIFIED: Self = Stratum(0);
642 pub const PRIMARY: Self = Stratum(1);
644 pub const SECONDARY_MIN: Self = Stratum(2);
646 pub const SECONDARY_MAX: Self = Stratum(15);
648 pub const UNSYNCHRONIZED: Self = Stratum(16);
650 pub const MAX: Self = Stratum(16);
652
653 pub fn is_secondary(&self) -> bool {
655 Self::SECONDARY_MIN <= *self && *self <= Self::SECONDARY_MAX
656 }
657
658 pub fn is_reserved(&self) -> bool {
660 *self > Self::MAX
661 }
662}
663
664impl ConstPackedSizeBytes for ShortFormat {
667 const PACKED_SIZE_BYTES: usize = 4;
668}
669
670impl ConstPackedSizeBytes for TimestampFormat {
671 const PACKED_SIZE_BYTES: usize = 8;
672}
673
674impl ConstPackedSizeBytes for DateFormat {
675 const PACKED_SIZE_BYTES: usize = 16;
676}
677
678impl ConstPackedSizeBytes for Stratum {
679 const PACKED_SIZE_BYTES: usize = 1;
680}
681
682impl ConstPackedSizeBytes for ReferenceIdentifier {
683 const PACKED_SIZE_BYTES: usize = 4;
684}
685
686impl ConstPackedSizeBytes for PacketByte1 {
687 const PACKED_SIZE_BYTES: usize = 1;
688}
689
690impl ConstPackedSizeBytes for Packet {
691 const PACKED_SIZE_BYTES: usize = PacketByte1::PACKED_SIZE_BYTES
692 + Stratum::PACKED_SIZE_BYTES
693 + 2
694 + ShortFormat::PACKED_SIZE_BYTES * 2
695 + ReferenceIdentifier::PACKED_SIZE_BYTES
696 + TimestampFormat::PACKED_SIZE_BYTES * 4;
697}
698
699#[cfg(feature = "std")]
702impl<W> WriteBytes for W
703where
704 W: WriteBytesExt,
705{
706 fn write_bytes<P: WriteToBytes>(&mut self, protocol: P) -> io::Result<()> {
707 protocol.write_to_bytes(self)
708 }
709}
710
711#[cfg(feature = "std")]
712impl<P> WriteToBytes for &P
713where
714 P: WriteToBytes,
715{
716 fn write_to_bytes<W: WriteBytesExt>(&self, writer: W) -> io::Result<()> {
717 (*self).write_to_bytes(writer)
718 }
719}
720
721#[cfg(feature = "std")]
722impl WriteToBytes for ShortFormat {
723 fn write_to_bytes<W: WriteBytesExt>(&self, mut writer: W) -> io::Result<()> {
724 writer.write_u16::<BE>(self.seconds)?;
725 writer.write_u16::<BE>(self.fraction)?;
726 Ok(())
727 }
728}
729
730#[cfg(feature = "std")]
731impl WriteToBytes for TimestampFormat {
732 fn write_to_bytes<W: WriteBytesExt>(&self, mut writer: W) -> io::Result<()> {
733 writer.write_u32::<BE>(self.seconds)?;
734 writer.write_u32::<BE>(self.fraction)?;
735 Ok(())
736 }
737}
738
739#[cfg(feature = "std")]
740impl WriteToBytes for DateFormat {
741 fn write_to_bytes<W: WriteBytesExt>(&self, mut writer: W) -> io::Result<()> {
742 writer.write_i32::<BE>(self.era_number)?;
743 writer.write_u32::<BE>(self.era_offset)?;
744 writer.write_u64::<BE>(self.fraction)?;
745 Ok(())
746 }
747}
748
749#[cfg(feature = "std")]
750impl WriteToBytes for Stratum {
751 fn write_to_bytes<W: WriteBytesExt>(&self, mut writer: W) -> io::Result<()> {
752 writer.write_u8(self.0)?;
753 Ok(())
754 }
755}
756
757#[cfg(feature = "std")]
758impl WriteToBytes for ReferenceIdentifier {
759 fn write_to_bytes<W: WriteBytesExt>(&self, mut writer: W) -> io::Result<()> {
760 match *self {
761 ReferenceIdentifier::KissOfDeath(kod) => {
762 writer.write_u32::<BE>(kod as u32)?;
763 }
764 ReferenceIdentifier::PrimarySource(src) => {
765 writer.write_u32::<BE>(src as u32)?;
766 }
767 ReferenceIdentifier::SecondaryOrClient(arr) => {
768 writer.write_u32::<BE>(code_to_u32!(&arr))?;
769 }
770 ReferenceIdentifier::Unknown(arr) => {
771 writer.write_u32::<BE>(code_to_u32!(&arr))?;
772 }
773 }
774 Ok(())
775 }
776}
777
778#[cfg(feature = "std")]
779impl WriteToBytes for (LeapIndicator, Version, Mode) {
780 fn write_to_bytes<W: WriteBytesExt>(&self, mut writer: W) -> io::Result<()> {
781 let (li, vn, mode) = *self;
782 let mut li_vn_mode = 0;
783 li_vn_mode |= (li as u8) << 6;
784 li_vn_mode |= vn.0 << 3;
785 li_vn_mode |= mode as u8;
786 writer.write_u8(li_vn_mode)?;
787 Ok(())
788 }
789}
790
791#[cfg(feature = "std")]
792impl WriteToBytes for Packet {
793 fn write_to_bytes<W: WriteBytesExt>(&self, mut writer: W) -> io::Result<()> {
794 let li_vn_mode = (self.leap_indicator, self.version, self.mode);
795 writer.write_bytes(li_vn_mode)?;
796 writer.write_bytes(self.stratum)?;
797 writer.write_i8(self.poll)?;
798 writer.write_i8(self.precision)?;
799 writer.write_bytes(self.root_delay)?;
800 writer.write_bytes(self.root_dispersion)?;
801 writer.write_bytes(self.reference_id)?;
802 writer.write_bytes(self.reference_timestamp)?;
803 writer.write_bytes(self.origin_timestamp)?;
804 writer.write_bytes(self.receive_timestamp)?;
805 writer.write_bytes(self.transmit_timestamp)?;
806 Ok(())
807 }
808}
809
810#[cfg(feature = "std")]
813impl<R> ReadBytes for R
814where
815 R: ReadBytesExt,
816{
817 fn read_bytes<P: ReadFromBytes>(&mut self) -> io::Result<P> {
818 P::read_from_bytes(self)
819 }
820}
821
822#[cfg(feature = "std")]
823impl ReadFromBytes for ShortFormat {
824 fn read_from_bytes<R: ReadBytesExt>(mut reader: R) -> io::Result<Self> {
825 let seconds = reader.read_u16::<BE>()?;
826 let fraction = reader.read_u16::<BE>()?;
827 let short_format = ShortFormat { seconds, fraction };
828 Ok(short_format)
829 }
830}
831
832#[cfg(feature = "std")]
833impl ReadFromBytes for TimestampFormat {
834 fn read_from_bytes<R: ReadBytesExt>(mut reader: R) -> io::Result<Self> {
835 let seconds = reader.read_u32::<BE>()?;
836 let fraction = reader.read_u32::<BE>()?;
837 let timestamp_format = TimestampFormat { seconds, fraction };
838 Ok(timestamp_format)
839 }
840}
841
842#[cfg(feature = "std")]
843impl ReadFromBytes for DateFormat {
844 fn read_from_bytes<R: ReadBytesExt>(mut reader: R) -> io::Result<Self> {
845 let era_number = reader.read_i32::<BE>()?;
846 let era_offset = reader.read_u32::<BE>()?;
847 let fraction = reader.read_u64::<BE>()?;
848 let date_format = DateFormat {
849 era_number,
850 era_offset,
851 fraction,
852 };
853 Ok(date_format)
854 }
855}
856
857#[cfg(feature = "std")]
858impl ReadFromBytes for Stratum {
859 fn read_from_bytes<R: ReadBytesExt>(mut reader: R) -> io::Result<Self> {
860 let stratum = Stratum(reader.read_u8()?);
861 Ok(stratum)
862 }
863}
864
865#[cfg(feature = "std")]
866impl ReadFromBytes for (LeapIndicator, Version, Mode) {
867 fn read_from_bytes<R: ReadBytesExt>(mut reader: R) -> io::Result<Self> {
868 let li_vn_mode = reader.read_u8()?;
869 let li_u8 = li_vn_mode >> 6;
870 let vn_u8 = (li_vn_mode >> 3) & 0b111;
871 let mode_u8 = li_vn_mode & 0b111;
872 let li = match LeapIndicator::try_from(li_u8).ok() {
873 Some(li) => li,
874 None => {
875 let err_msg = "unknown leap indicator";
876 return Err(io::Error::new(io::ErrorKind::InvalidData, err_msg));
877 }
878 };
879 let vn = Version(vn_u8);
880 let mode = match Mode::try_from(mode_u8).ok() {
881 Some(mode) => mode,
882 None => {
883 let err_msg = "unknown association mode";
884 return Err(io::Error::new(io::ErrorKind::InvalidData, err_msg));
885 }
886 };
887 Ok((li, vn, mode))
888 }
889}
890
891#[cfg(feature = "std")]
892impl ReadFromBytes for Packet {
893 fn read_from_bytes<R: ReadBytesExt>(mut reader: R) -> io::Result<Self> {
894 let (leap_indicator, version, mode) = reader.read_bytes()?;
895 let stratum = reader.read_bytes::<Stratum>()?;
896 let poll = reader.read_i8()?;
897 let precision = reader.read_i8()?;
898 let root_delay = reader.read_bytes()?;
899 let root_dispersion = reader.read_bytes()?;
900 let reference_id = {
901 let u = reader.read_u32::<BE>()?;
902 let raw_bytes = be_u32_to_bytes(u);
903 if stratum == Stratum::UNSPECIFIED {
904 match KissOfDeath::try_from(u) {
906 Ok(kod) => ReferenceIdentifier::KissOfDeath(kod),
907 Err(_) => ReferenceIdentifier::Unknown(raw_bytes),
908 }
909 } else if stratum == Stratum::PRIMARY {
910 match PrimarySource::try_from(u) {
912 Ok(src) => ReferenceIdentifier::PrimarySource(src),
913 Err(_) => ReferenceIdentifier::Unknown(raw_bytes),
914 }
915 } else if stratum.is_secondary() {
916 ReferenceIdentifier::SecondaryOrClient(raw_bytes)
918 } else {
919 ReferenceIdentifier::Unknown(raw_bytes)
921 }
922 };
923 let reference_timestamp = reader.read_bytes()?;
924 let origin_timestamp = reader.read_bytes()?;
925 let receive_timestamp = reader.read_bytes()?;
926 let transmit_timestamp = reader.read_bytes()?;
927 Ok(Packet {
928 leap_indicator,
929 version,
930 mode,
931 stratum,
932 poll,
933 precision,
934 root_delay,
935 root_dispersion,
936 reference_id,
937 reference_timestamp,
938 origin_timestamp,
939 receive_timestamp,
940 transmit_timestamp,
941 })
942 }
943}
944
945impl fmt::Display for PrimarySource {
948 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
949 let bytes = self.bytes();
950 for &b in &bytes {
951 if b == 0 {
952 break;
953 }
954 if b.is_ascii() {
955 write!(f, "{}", b as char)?;
956 } else {
957 write!(f, "?")?;
958 }
959 }
960 Ok(())
961 }
962}
963
964impl FromBytes for ShortFormat {
967 fn from_bytes(buf: &[u8]) -> Result<(Self, usize), ParseError> {
968 if buf.len() < Self::PACKED_SIZE_BYTES {
969 return Err(ParseError::BufferTooShort {
970 needed: Self::PACKED_SIZE_BYTES,
971 available: buf.len(),
972 });
973 }
974 let seconds = u16::from_be_bytes([buf[0], buf[1]]);
975 let fraction = u16::from_be_bytes([buf[2], buf[3]]);
976 Ok((ShortFormat { seconds, fraction }, Self::PACKED_SIZE_BYTES))
977 }
978}
979
980impl FromBytes for TimestampFormat {
981 fn from_bytes(buf: &[u8]) -> Result<(Self, usize), ParseError> {
982 if buf.len() < Self::PACKED_SIZE_BYTES {
983 return Err(ParseError::BufferTooShort {
984 needed: Self::PACKED_SIZE_BYTES,
985 available: buf.len(),
986 });
987 }
988 let seconds = u32::from_be_bytes([buf[0], buf[1], buf[2], buf[3]]);
989 let fraction = u32::from_be_bytes([buf[4], buf[5], buf[6], buf[7]]);
990 Ok((
991 TimestampFormat { seconds, fraction },
992 Self::PACKED_SIZE_BYTES,
993 ))
994 }
995}
996
997impl FromBytes for DateFormat {
998 fn from_bytes(buf: &[u8]) -> Result<(Self, usize), ParseError> {
999 if buf.len() < Self::PACKED_SIZE_BYTES {
1000 return Err(ParseError::BufferTooShort {
1001 needed: Self::PACKED_SIZE_BYTES,
1002 available: buf.len(),
1003 });
1004 }
1005 let era_number = i32::from_be_bytes([buf[0], buf[1], buf[2], buf[3]]);
1006 let era_offset = u32::from_be_bytes([buf[4], buf[5], buf[6], buf[7]]);
1007 let fraction = u64::from_be_bytes([
1008 buf[8], buf[9], buf[10], buf[11], buf[12], buf[13], buf[14], buf[15],
1009 ]);
1010 Ok((
1011 DateFormat {
1012 era_number,
1013 era_offset,
1014 fraction,
1015 },
1016 Self::PACKED_SIZE_BYTES,
1017 ))
1018 }
1019}
1020
1021impl FromBytes for Stratum {
1022 fn from_bytes(buf: &[u8]) -> Result<(Self, usize), ParseError> {
1023 if buf.is_empty() {
1024 return Err(ParseError::BufferTooShort {
1025 needed: 1,
1026 available: 0,
1027 });
1028 }
1029 Ok((Stratum(buf[0]), 1))
1030 }
1031}
1032
1033impl FromBytes for (LeapIndicator, Version, Mode) {
1034 fn from_bytes(buf: &[u8]) -> Result<(Self, usize), ParseError> {
1035 if buf.is_empty() {
1036 return Err(ParseError::BufferTooShort {
1037 needed: 1,
1038 available: 0,
1039 });
1040 }
1041 let li_vn_mode = buf[0];
1042 let li_u8 = li_vn_mode >> 6;
1043 let vn_u8 = (li_vn_mode >> 3) & 0b111;
1044 let mode_u8 = li_vn_mode & 0b111;
1045 let li = LeapIndicator::try_from(li_u8).map_err(|_| ParseError::InvalidField {
1046 field: "leap indicator",
1047 value: li_u8 as u32,
1048 })?;
1049 let vn = Version(vn_u8);
1050 let mode = Mode::try_from(mode_u8).map_err(|_| ParseError::InvalidField {
1051 field: "association mode",
1052 value: mode_u8 as u32,
1053 })?;
1054 Ok(((li, vn, mode), 1))
1055 }
1056}
1057
1058impl ReferenceIdentifier {
1059 pub fn from_bytes_with_stratum(bytes: [u8; 4], stratum: Stratum) -> Self {
1067 let u = u32::from_be_bytes(bytes);
1068 if stratum == Stratum::UNSPECIFIED {
1069 match KissOfDeath::try_from(u) {
1070 Ok(kod) => ReferenceIdentifier::KissOfDeath(kod),
1071 Err(_) => ReferenceIdentifier::Unknown(bytes),
1072 }
1073 } else if stratum == Stratum::PRIMARY {
1074 match PrimarySource::try_from(u) {
1075 Ok(src) => ReferenceIdentifier::PrimarySource(src),
1076 Err(_) => ReferenceIdentifier::Unknown(bytes),
1077 }
1078 } else if stratum.is_secondary() {
1079 ReferenceIdentifier::SecondaryOrClient(bytes)
1080 } else {
1081 ReferenceIdentifier::Unknown(bytes)
1082 }
1083 }
1084}
1085
1086impl FromBytes for Packet {
1087 fn from_bytes(buf: &[u8]) -> Result<(Self, usize), ParseError> {
1088 if buf.len() < Self::PACKED_SIZE_BYTES {
1089 return Err(ParseError::BufferTooShort {
1090 needed: Self::PACKED_SIZE_BYTES,
1091 available: buf.len(),
1092 });
1093 }
1094
1095 let mut offset = 0;
1096
1097 let ((leap_indicator, version, mode), n) =
1098 <(LeapIndicator, Version, Mode)>::from_bytes(&buf[offset..])?;
1099 offset += n;
1100
1101 let (stratum, n) = Stratum::from_bytes(&buf[offset..])?;
1102 offset += n;
1103
1104 let poll = buf[offset] as i8;
1105 offset += 1;
1106
1107 let precision = buf[offset] as i8;
1108 offset += 1;
1109
1110 let (root_delay, n) = ShortFormat::from_bytes(&buf[offset..])?;
1111 offset += n;
1112
1113 let (root_dispersion, n) = ShortFormat::from_bytes(&buf[offset..])?;
1114 offset += n;
1115
1116 let ref_id_bytes = [
1117 buf[offset],
1118 buf[offset + 1],
1119 buf[offset + 2],
1120 buf[offset + 3],
1121 ];
1122 let reference_id = ReferenceIdentifier::from_bytes_with_stratum(ref_id_bytes, stratum);
1123 offset += 4;
1124
1125 let (reference_timestamp, n) = TimestampFormat::from_bytes(&buf[offset..])?;
1126 offset += n;
1127
1128 let (origin_timestamp, n) = TimestampFormat::from_bytes(&buf[offset..])?;
1129 offset += n;
1130
1131 let (receive_timestamp, n) = TimestampFormat::from_bytes(&buf[offset..])?;
1132 offset += n;
1133
1134 let (transmit_timestamp, n) = TimestampFormat::from_bytes(&buf[offset..])?;
1135 offset += n;
1136
1137 Ok((
1138 Packet {
1139 leap_indicator,
1140 version,
1141 mode,
1142 stratum,
1143 poll,
1144 precision,
1145 root_delay,
1146 root_dispersion,
1147 reference_id,
1148 reference_timestamp,
1149 origin_timestamp,
1150 receive_timestamp,
1151 transmit_timestamp,
1152 },
1153 offset,
1154 ))
1155 }
1156}
1157
1158impl ToBytes for ShortFormat {
1161 fn to_bytes(&self, buf: &mut [u8]) -> Result<usize, ParseError> {
1162 if buf.len() < Self::PACKED_SIZE_BYTES {
1163 return Err(ParseError::BufferTooShort {
1164 needed: Self::PACKED_SIZE_BYTES,
1165 available: buf.len(),
1166 });
1167 }
1168 let s = self.seconds.to_be_bytes();
1169 let f = self.fraction.to_be_bytes();
1170 buf[0] = s[0];
1171 buf[1] = s[1];
1172 buf[2] = f[0];
1173 buf[3] = f[1];
1174 Ok(Self::PACKED_SIZE_BYTES)
1175 }
1176}
1177
1178impl ToBytes for TimestampFormat {
1179 fn to_bytes(&self, buf: &mut [u8]) -> Result<usize, ParseError> {
1180 if buf.len() < Self::PACKED_SIZE_BYTES {
1181 return Err(ParseError::BufferTooShort {
1182 needed: Self::PACKED_SIZE_BYTES,
1183 available: buf.len(),
1184 });
1185 }
1186 let s = self.seconds.to_be_bytes();
1187 let f = self.fraction.to_be_bytes();
1188 buf[..4].copy_from_slice(&s);
1189 buf[4..8].copy_from_slice(&f);
1190 Ok(Self::PACKED_SIZE_BYTES)
1191 }
1192}
1193
1194impl ToBytes for DateFormat {
1195 fn to_bytes(&self, buf: &mut [u8]) -> Result<usize, ParseError> {
1196 if buf.len() < Self::PACKED_SIZE_BYTES {
1197 return Err(ParseError::BufferTooShort {
1198 needed: Self::PACKED_SIZE_BYTES,
1199 available: buf.len(),
1200 });
1201 }
1202 buf[..4].copy_from_slice(&self.era_number.to_be_bytes());
1203 buf[4..8].copy_from_slice(&self.era_offset.to_be_bytes());
1204 buf[8..16].copy_from_slice(&self.fraction.to_be_bytes());
1205 Ok(Self::PACKED_SIZE_BYTES)
1206 }
1207}
1208
1209impl ToBytes for Stratum {
1210 fn to_bytes(&self, buf: &mut [u8]) -> Result<usize, ParseError> {
1211 if buf.is_empty() {
1212 return Err(ParseError::BufferTooShort {
1213 needed: 1,
1214 available: 0,
1215 });
1216 }
1217 buf[0] = self.0;
1218 Ok(1)
1219 }
1220}
1221
1222impl ToBytes for (LeapIndicator, Version, Mode) {
1223 fn to_bytes(&self, buf: &mut [u8]) -> Result<usize, ParseError> {
1224 if buf.is_empty() {
1225 return Err(ParseError::BufferTooShort {
1226 needed: 1,
1227 available: 0,
1228 });
1229 }
1230 let (li, vn, mode) = *self;
1231 let mut li_vn_mode = 0u8;
1232 li_vn_mode |= (li as u8) << 6;
1233 li_vn_mode |= vn.0 << 3;
1234 li_vn_mode |= mode as u8;
1235 buf[0] = li_vn_mode;
1236 Ok(1)
1237 }
1238}
1239
1240impl ToBytes for ReferenceIdentifier {
1241 fn to_bytes(&self, buf: &mut [u8]) -> Result<usize, ParseError> {
1242 if buf.len() < Self::PACKED_SIZE_BYTES {
1243 return Err(ParseError::BufferTooShort {
1244 needed: Self::PACKED_SIZE_BYTES,
1245 available: buf.len(),
1246 });
1247 }
1248 let bytes = self.as_bytes();
1249 buf[..4].copy_from_slice(&bytes);
1250 Ok(Self::PACKED_SIZE_BYTES)
1251 }
1252}
1253
1254impl ToBytes for Packet {
1255 fn to_bytes(&self, buf: &mut [u8]) -> Result<usize, ParseError> {
1256 if buf.len() < Self::PACKED_SIZE_BYTES {
1257 return Err(ParseError::BufferTooShort {
1258 needed: Self::PACKED_SIZE_BYTES,
1259 available: buf.len(),
1260 });
1261 }
1262
1263 let mut offset = 0;
1264
1265 let li_vn_mode = (self.leap_indicator, self.version, self.mode);
1266 offset += li_vn_mode.to_bytes(&mut buf[offset..])?;
1267 offset += self.stratum.to_bytes(&mut buf[offset..])?;
1268 buf[offset] = self.poll as u8;
1269 offset += 1;
1270 buf[offset] = self.precision as u8;
1271 offset += 1;
1272 offset += self.root_delay.to_bytes(&mut buf[offset..])?;
1273 offset += self.root_dispersion.to_bytes(&mut buf[offset..])?;
1274 offset += self.reference_id.to_bytes(&mut buf[offset..])?;
1275 offset += self.reference_timestamp.to_bytes(&mut buf[offset..])?;
1276 offset += self.origin_timestamp.to_bytes(&mut buf[offset..])?;
1277 offset += self.receive_timestamp.to_bytes(&mut buf[offset..])?;
1278 offset += self.transmit_timestamp.to_bytes(&mut buf[offset..])?;
1279
1280 Ok(offset)
1281 }
1282}
1283
1284fn be_u32_to_bytes(u: u32) -> [u8; 4] {
1287 [
1288 (u >> 24 & 0xff) as u8,
1289 (u >> 16 & 0xff) as u8,
1290 (u >> 8 & 0xff) as u8,
1291 (u & 0xff) as u8,
1292 ]
1293}