1use std::ops;
2
3#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
8pub struct Millis(pub u32);
9
10impl Millis {
11 pub const ZERO: Millis = Millis(0);
13
14 pub const ONE_SEC: Millis = Millis(1_000);
16
17 #[inline]
18 pub const fn from_secs(secs: u32) -> Millis {
19 Millis(secs * 1000)
20 }
21
22 #[inline]
23 pub const fn is_zero(&self) -> bool {
24 self.0 == 0
25 }
26
27 #[inline]
28 pub const fn non_zero(self) -> bool {
29 self.0 != 0
30 }
31
32 #[inline]
34 pub fn map<F, R>(&self, f: F) -> Option<R>
35 where
36 F: FnOnce(Millis) -> R,
37 {
38 if self.0 == 0 { None } else { Some(f(*self)) }
39 }
40}
41
42impl Default for Millis {
43 #[inline]
44 fn default() -> Millis {
45 Millis::ZERO
46 }
47}
48
49impl ops::Add<Millis> for Millis {
50 type Output = Millis;
51
52 #[inline]
53 fn add(self, other: Millis) -> Millis {
54 Millis(self.0.saturating_add(other.0))
55 }
56}
57
58impl ops::Add<Seconds> for Millis {
59 type Output = Millis;
60
61 #[inline]
62 #[allow(clippy::suspicious_arithmetic_impl)]
63 fn add(self, other: Seconds) -> Millis {
64 Millis(
65 self.0
66 .saturating_add((u32::from(other.0)).saturating_mul(1000)),
67 )
68 }
69}
70
71impl ops::Add<std::time::Duration> for Millis {
72 type Output = Millis;
73
74 #[inline]
75 fn add(self, other: std::time::Duration) -> Millis {
76 self + Millis::from(other)
77 }
78}
79
80impl ops::Add<Millis> for std::time::Duration {
81 type Output = std::time::Duration;
82
83 #[inline]
84 fn add(self, other: Millis) -> std::time::Duration {
85 self + Self::from(other)
86 }
87}
88
89impl From<u32> for Millis {
90 #[inline]
91 fn from(s: u32) -> Millis {
92 Millis(s)
93 }
94}
95
96impl From<i32> for Millis {
97 #[inline]
98 fn from(i: i32) -> Millis {
99 Millis(if i < 0 { 0 } else { i as u32 })
100 }
101}
102
103impl From<usize> for Millis {
104 #[inline]
105 fn from(s: usize) -> Millis {
106 Self(s.try_into().unwrap_or_else(|_| {
107 log::error!("Values is too large {s:?}");
108 u32::MAX
109 }))
110 }
111}
112
113impl From<Seconds> for Millis {
114 #[inline]
115 fn from(s: Seconds) -> Millis {
116 Millis((u32::from(s.0)).saturating_mul(1000))
117 }
118}
119
120impl From<std::time::Duration> for Millis {
121 #[inline]
122 fn from(d: std::time::Duration) -> Millis {
123 Self(d.as_millis().try_into().unwrap_or_else(|_| {
124 log::error!("time Duration is too large {d:?}");
125 1 << 31
126 }))
127 }
128}
129
130impl From<Millis> for std::time::Duration {
131 #[inline]
132 fn from(d: Millis) -> std::time::Duration {
133 std::time::Duration::from_millis(u64::from(d.0))
134 }
135}
136
137#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
139pub struct Seconds(pub u16);
140
141impl Seconds {
142 pub const ZERO: Seconds = Seconds(0);
144
145 pub const ONE: Seconds = Seconds(1);
147
148 #[inline]
149 pub const fn new(secs: u16) -> Seconds {
150 Seconds(secs)
151 }
152
153 #[inline]
154 pub const fn checked_new(secs: usize) -> Seconds {
155 let secs = if (u16::MAX as usize) < secs {
156 u16::MAX
157 } else {
158 secs as u16
159 };
160 Seconds(secs)
161 }
162
163 #[inline]
164 pub const fn is_zero(self) -> bool {
165 self.0 == 0
166 }
167
168 #[inline]
169 pub const fn non_zero(self) -> bool {
170 self.0 != 0
171 }
172
173 #[inline]
174 pub const fn seconds(self) -> u64 {
175 self.0 as u64
176 }
177
178 #[inline]
180 pub fn map<F, R>(&self, f: F) -> Option<R>
181 where
182 F: FnOnce(Millis) -> R,
183 {
184 if self.0 == 0 {
185 None
186 } else {
187 Some(f(Millis::from(*self)))
188 }
189 }
190}
191
192impl Default for Seconds {
193 #[inline]
194 fn default() -> Seconds {
195 Seconds::ZERO
196 }
197}
198
199impl ops::Add<Seconds> for Seconds {
200 type Output = Seconds;
201
202 #[inline]
203 fn add(self, other: Seconds) -> Seconds {
204 Seconds(self.0.saturating_add(other.0))
205 }
206}
207
208impl From<Seconds> for std::time::Duration {
209 #[inline]
210 fn from(d: Seconds) -> std::time::Duration {
211 std::time::Duration::from_secs(u64::from(d.0))
212 }
213}
214
215impl From<u16> for Seconds {
216 #[inline]
217 fn from(secs: u16) -> Seconds {
218 Self(secs)
219 }
220}
221
222impl From<i32> for Seconds {
223 #[inline]
224 fn from(i: i32) -> Seconds {
225 Seconds(if i < 0 { 0 } else { i as u16 })
226 }
227}
228
229impl From<usize> for Seconds {
230 #[inline]
231 fn from(secs: usize) -> Seconds {
232 Self(secs.try_into().unwrap_or_else(|_| {
233 log::error!("Seconds value is too large {secs:?}");
234 u16::MAX
235 }))
236 }
237}
238
239#[cfg(test)]
240mod tests {
241 use super::*;
242 use std::time::Duration;
243
244 #[test]
245 fn time_types() {
246 let m = Millis::default();
247 assert_eq!(m.0, 0);
248
249 let m = Millis::from(10u32);
250 assert_eq!(m.0, 10);
251
252 let m = Millis::from(10usize);
253 assert_eq!(m.0, 10);
254
255 let m = Millis(10) + Millis(20);
256 assert_eq!(m.0, 30);
257
258 let m = Millis(10) + Millis(u32::MAX);
259 assert_eq!(m.0, u32::MAX);
260
261 let m = Millis(10) + Seconds(1);
262 assert_eq!(m.0, 1010);
263
264 let m = Millis(u32::MAX) + Seconds(1);
265 assert_eq!(m.0, u32::MAX);
266
267 let m = Millis(10) + Duration::from_millis(100);
268 assert_eq!(m.0, 110);
269
270 let m = Duration::from_millis(100) + Millis(10);
271 assert_eq!(m, Duration::from_millis(110));
272
273 let m = Millis::from(Seconds(1));
274 assert_eq!(m.0, 1000);
275
276 let m = Millis::from(Duration::from_secs(1));
277 assert_eq!(m.0, 1000);
278
279 let m = Millis::from(Duration::from_secs(u64::MAX));
280 assert_eq!(m.0, 2_147_483_648);
281
282 let m = Millis::from_secs(1);
283 assert_eq!(m.0, 1000);
284
285 let m = Millis(0);
286 assert_eq!(m.map(|m| m + Millis(1)), None);
287
288 let m = Millis(1);
289 assert_eq!(m.map(|m| m + Millis(1)), Some(Millis(2)));
290
291 let s = Seconds::new(10);
292 assert_eq!(s.0, 10);
293
294 let s = Seconds::from(10u16);
295 assert_eq!(s.0, 10);
296
297 let s = Seconds::from(10usize);
298 assert_eq!(s.0, 10);
299
300 let s = Seconds::from(10i32);
301 assert_eq!(s.0, 10);
302
303 let s = Seconds::from(-10i32);
304 assert_eq!(s.0, 0);
305
306 let s = Seconds::checked_new(10);
307 assert_eq!(s.0, 10);
308
309 let s = Seconds::checked_new(u16::MAX as usize + 10);
310 assert_eq!(s.0, u16::MAX);
311
312 assert!(Seconds::ZERO.is_zero());
313 assert!(!Seconds::ZERO.non_zero());
314
315 let s = Seconds::new(10);
316 assert_eq!(s.seconds(), 10);
317
318 let s = Seconds::default();
319 assert_eq!(s.0, 0);
320
321 let s = Seconds::new(10) + Seconds::new(10);
322 assert_eq!(s.seconds(), 20);
323
324 assert_eq!(Seconds(0).map(|_| 1usize), None);
325 assert_eq!(Seconds(2).map(|_| 1usize), Some(1));
326
327 let d = Duration::from(Seconds(100));
328 assert_eq!(d.as_secs(), 100);
329 }
330}