statime_wire/common/
time_interval.rs1use statime_base::Duration;
2
3use crate::Error;
4
5#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
7#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
8pub struct TimeInterval(
9 pub i64,
11);
12
13impl From<TimeInterval> for Duration {
14 fn from(value: TimeInterval) -> Self {
15 Duration::from_raw_steps((i128::from(value.0) << 48) / 1_000_000_000)
16 }
17}
18
19impl TimeInterval {
20 pub fn serialize(self, buffer: &mut [u8]) -> Result<(), Error> {
25 buffer
26 .get_mut(0..8)
27 .ok_or(Error::BufferTooShort)?
28 .copy_from_slice(&self.0.to_be_bytes());
29 Ok(())
30 }
31
32 #[allow(
37 clippy::missing_panics_doc,
38 reason = "Clippy can't tell the try_into will never fail"
39 )]
40 pub fn deserialize(buffer: &[u8]) -> Result<Self, Error> {
41 Ok(Self(i64::from_be_bytes(
42 buffer
43 .get(0..8)
44 .ok_or(Error::BufferTooShort)?
45 .try_into()
46 .unwrap(),
47 )))
48 }
49
50 #[must_use]
52 #[expect(
53 clippy::cast_precision_loss,
54 reason = "Precision loss here is acceptable as it only happens when the interval is relatively large"
55 )]
56 pub fn to_nanos(self) -> f64 {
57 (self.0 as f64) / f64::from(1 << 16)
58 }
59
60 pub fn from_nanos(nanos: f64) -> Result<Self, Error> {
68 let ticks = nanos * f64::from(1 << 16);
71 #[expect(clippy::cast_precision_loss)]
76 #[expect(clippy::cast_possible_truncation)]
77 if ticks.is_nan() || ticks >= (i64::MAX as f64) || ticks < (i64::MIN as f64) {
78 Err(Error::Invalid)
79 } else {
80 Ok(Self((nanos * f64::from(1 << 16)) as i64))
81 }
82 }
83}
84
85#[cfg(test)]
86mod tests {
87 use super::*;
88
89 #[test]
90 fn time_interval_wireformat() {
91 let representations = [
92 (
93 [0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x80, 0x00u8],
94 TimeInterval::from_nanos(2.5f64).unwrap(),
95 ),
96 (
97 [0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01u8],
98 TimeInterval::from_nanos(1.0f64 / f64::from(u16::MAX)).unwrap(),
99 ),
100 (
101 [0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00u8],
102 TimeInterval::from_nanos(-1.0f64).unwrap(),
103 ),
104 ];
105
106 for (byte_representation, object_representation) in representations {
107 let mut serialization_buffer = [0; 8];
109 object_representation
110 .serialize(&mut serialization_buffer)
111 .unwrap();
112 assert_eq!(serialization_buffer, byte_representation);
113
114 let deserialized_data = TimeInterval::deserialize(&byte_representation).unwrap();
116 assert_eq!(deserialized_data, object_representation);
117 }
118 }
119}