1use std::{fmt, ops::Div};
2
3use speedy::{Readable, Writable};
4use serde::{Deserialize, Serialize};
5
6#[derive(
7 PartialEq, Eq, Hash, PartialOrd, Ord, Readable, Writable, Serialize, Deserialize, Copy, Clone,
8)]
9pub struct Duration {
16 seconds: i32,
17 fraction: u32, }
19
20impl Duration {
21 pub const ZERO: Self = Self {
22 seconds: 0,
23 fraction: 0,
24 };
25
26 pub const INFINITE: Self = Self {
27 seconds: 0x7FFFFFFF,
28 fraction: 0xFFFFFFFF,
29 };
30
31 #[deprecated(since = "0.8.7", note = "Renamed to Duration::ZERO")]
32 pub const DURATION_ZERO: Self = Self::ZERO;
33
34 #[deprecated(since = "0.8.7", note = "Renamed to Duration::INFINITE")]
35 pub const DURATION_INFINITE: Self = Self::INFINITE;
36
37 pub const fn from_secs(secs: i32) -> Self {
38 Self {
39 seconds: secs, fraction: 0,
41 }
42 }
43
44 pub fn from_frac_seconds(secs: f64) -> Self {
45 Self {
46 seconds: secs.trunc() as i32,
47 fraction: (secs.fract().abs() * 32.0_f64.exp2()) as u32,
48 }
49 }
50
51 pub const fn from_millis(millis: i64) -> Self {
52 let fraction = (((millis % 1000) << 32) / 1000) as u32;
53
54 Self {
55 seconds: (millis / 1000) as i32,
56 fraction,
57 }
58 }
59
60 pub const fn from_nanos(nanos: i64) -> Self {
61 let fraction = (((nanos % 1_000_000_000) << 32) / 1_000_000_000) as u32;
62
63 Self {
64 seconds: (nanos / 1_000_000_000) as i32,
65 fraction,
66 }
67 }
68
69 pub(crate) fn to_ticks(self) -> i64 {
70 (i64::from(self.seconds) << 32) + i64::from(self.fraction)
71 }
72
73 pub(crate) fn from_ticks(ticks: i64) -> Self {
74 Self {
75 seconds: (ticks >> 32) as i32,
76 fraction: ticks as u32,
77 }
78 }
79
80 pub fn to_nanoseconds(&self) -> i64 {
81 ((i128::from(self.to_ticks()) * 1_000_000_000) >> 32) as i64
82 }
83
84 pub fn from_std(duration: std::time::Duration) -> Self {
85 Self::from(duration)
86 }
87
88 pub fn to_std(&self) -> std::time::Duration {
89 std::time::Duration::from(*self)
90 }
91}
92
93impl From<Duration> for chrono::Duration {
94 fn from(d: Duration) -> Self {
95 Self::nanoseconds(d.to_nanoseconds())
96 }
97}
98
99impl From<std::time::Duration> for Duration {
100 fn from(duration: std::time::Duration) -> Self {
101 Self {
102 seconds: duration.as_secs() as i32,
103 fraction: ((u64::from(duration.subsec_nanos()) << 32) / 1_000_000_000) as u32,
104 }
105 }
106}
107
108impl From<Duration> for std::time::Duration {
109 fn from(d: Duration) -> Self {
110 Self::from_nanos(
111 u64::try_from(d.to_nanoseconds()).unwrap_or(0), )
114 }
115}
116
117impl Div<i64> for Duration {
118 type Output = Self;
119
120 fn div(self, rhs: i64) -> Self {
121 Self::from_ticks(self.to_ticks() / rhs)
122 }
123}
124
125impl std::ops::Add for Duration {
126 type Output = Self;
127 fn add(self, other: Self) -> Self {
128 Self::from_ticks(self.to_ticks() + other.to_ticks())
129 }
130}
131
132impl std::ops::Mul<Duration> for f64 {
133 type Output = Duration;
134 fn mul(self, rhs: Duration) -> Duration {
135 Duration::from_ticks((self * (rhs.to_ticks() as Self)) as i64)
136 }
137}
138
139impl fmt::Debug for Duration {
140 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
141 if *self == Self::INFINITE {
142 write!(f, "infinite")
143 } else {
144 write!(f, "{}", self.seconds)?;
145 if self.fraction > 0 {
146 let frac = format!("{:09}", (1_000_000_000 * (self.fraction as u64)) >> 32);
147 write!(f, ".{}", frac.trim_end_matches('0'))?;
148 }
149 write!(f, " sec")
150 }
151 }
152}
153
154#[cfg(test)]
155mod tests {
156 use super::*;
157
158 serialization_test!( type = Duration,
159 {
160 duration_zero,
161 Duration::ZERO,
162 le = [0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00],
163 be = [0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]
164 },
165 {
166 duration_infinite,
167 Duration::INFINITE,
168 le = [0xFF, 0xFF, 0xFF, 0x7F, 0xFF, 0xFF, 0xFF, 0xFF],
169 be = [0x7F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF]
170 },
171 {
172 duration_current_empty_fraction,
173 Duration { seconds: 1_537_045_491, fraction: 0 },
174 le = [0xF3, 0x73, 0x9D, 0x5B, 0x00, 0x00, 0x00, 0x00],
175 be = [0x5B, 0x9D, 0x73, 0xF3, 0x00, 0x00, 0x00, 0x00]
176 },
177 {
178 duration_from_wireshark,
179 Duration { seconds: 1_519_152_760, fraction: 1_328_210_046 },
180 le = [0x78, 0x6E, 0x8C, 0x5A, 0x7E, 0xE0, 0x2A, 0x4F],
181 be = [0x5A, 0x8C, 0x6E, 0x78, 0x4F, 0x2A, 0xE0, 0x7E]
182 });
183
184 const NANOS_PER_SEC: u64 = 1_000_000_000;
185
186 #[test]
187 fn convert_from_duration() {
188 let duration = std::time::Duration::from_nanos(1_519_152_761 * NANOS_PER_SEC + 328_210_046);
189 let duration: Duration = duration.into();
190
191 assert_eq!(
192 duration,
193 Duration {
194 seconds: 1_519_152_761,
195 fraction: 1_409_651_413,
196 }
197 );
198 }
199
200 #[test]
201 fn convert_to_duration() {
202 let duration = Duration {
203 seconds: 1_519_152_760,
204 fraction: 1_328_210_046,
205 };
206 let duration: std::time::Duration = duration.into();
207
208 assert_eq!(
209 duration,
210 std::time::Duration::from_nanos(1_519_152_760 * NANOS_PER_SEC + 309_247_999)
211 );
212 }
213
214 fn fmt_check(d: Duration, s: &str) {
215 assert_eq!(format!("{:?}", d), s);
216 }
217
218 #[test]
219 fn duration_format() {
220 fmt_check(Duration::from_frac_seconds(0.0), "0 sec");
221 fmt_check(Duration::from_frac_seconds(0.5), "0.5 sec");
222 fmt_check(Duration::from_frac_seconds(1.5), "1.5 sec");
223 fmt_check(Duration::from_frac_seconds(20.0), "20 sec");
224 fmt_check(Duration::from_frac_seconds(2.25), "2.25 sec");
225 fmt_check(Duration::from_frac_seconds(10.0 / 3.0), "3.333333333 sec");
226 }
227}