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 {
39 None
40 } else {
41 Some(f(*self))
42 }
43 }
44}
45
46impl Default for Millis {
47 #[inline]
48 fn default() -> Millis {
49 Millis::ZERO
50 }
51}
52
53impl ops::Add<Millis> for Millis {
54 type Output = Millis;
55
56 #[inline]
57 fn add(self, other: Millis) -> Millis {
58 Millis(self.0.saturating_add(other.0))
59 }
60}
61
62impl ops::Add<Seconds> for Millis {
63 type Output = Millis;
64
65 #[inline]
66 #[allow(clippy::suspicious_arithmetic_impl)]
67 fn add(self, other: Seconds) -> Millis {
68 Millis(self.0.saturating_add((other.0 as u32).saturating_mul(1000)))
69 }
70}
71
72impl ops::Add<std::time::Duration> for Millis {
73 type Output = Millis;
74
75 #[inline]
76 fn add(self, other: std::time::Duration) -> Millis {
77 self + Millis::from(other)
78 }
79}
80
81impl ops::Add<Millis> for std::time::Duration {
82 type Output = std::time::Duration;
83
84 #[inline]
85 fn add(self, other: Millis) -> std::time::Duration {
86 self + Self::from(other)
87 }
88}
89
90impl From<Seconds> for Millis {
91 #[inline]
92 fn from(s: Seconds) -> Millis {
93 Millis((s.0 as u32).saturating_mul(1000))
94 }
95}
96
97impl From<std::time::Duration> for Millis {
98 #[inline]
99 fn from(d: std::time::Duration) -> Millis {
100 Self(d.as_millis().try_into().unwrap_or_else(|_| {
101 log::error!("time Duration is too large {d:?}");
102 1 << 31
103 }))
104 }
105}
106
107impl From<Millis> for std::time::Duration {
108 #[inline]
109 fn from(d: Millis) -> std::time::Duration {
110 std::time::Duration::from_millis(d.0 as u64)
111 }
112}
113
114#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
116pub struct Seconds(pub u16);
117
118impl Seconds {
119 pub const ZERO: Seconds = Seconds(0);
121
122 pub const ONE: Seconds = Seconds(1);
124
125 #[inline]
126 pub const fn new(secs: u16) -> Seconds {
127 Seconds(secs)
128 }
129
130 #[inline]
131 pub const fn checked_new(secs: usize) -> Seconds {
132 let secs = if (u16::MAX as usize) < secs {
133 u16::MAX
134 } else {
135 secs as u16
136 };
137 Seconds(secs)
138 }
139
140 #[inline]
141 pub const fn is_zero(self) -> bool {
142 self.0 == 0
143 }
144
145 #[inline]
146 pub const fn non_zero(self) -> bool {
147 self.0 != 0
148 }
149
150 #[inline]
151 pub const fn seconds(self) -> u64 {
152 self.0 as u64
153 }
154
155 #[inline]
157 pub fn map<F, R>(&self, f: F) -> Option<R>
158 where
159 F: FnOnce(Millis) -> R,
160 {
161 if self.0 == 0 {
162 None
163 } else {
164 Some(f(Millis::from(*self)))
165 }
166 }
167}
168
169impl Default for Seconds {
170 #[inline]
171 fn default() -> Seconds {
172 Seconds::ZERO
173 }
174}
175
176impl ops::Add<Seconds> for Seconds {
177 type Output = Seconds;
178
179 #[inline]
180 fn add(self, other: Seconds) -> Seconds {
181 Seconds(self.0.saturating_add(other.0))
182 }
183}
184
185impl From<Seconds> for std::time::Duration {
186 #[inline]
187 fn from(d: Seconds) -> std::time::Duration {
188 std::time::Duration::from_secs(d.0 as u64)
189 }
190}
191
192#[cfg(test)]
193mod tests {
194 use super::*;
195 use std::time::Duration;
196
197 #[test]
198 fn time_types() {
199 let m = Millis::default();
200 assert_eq!(m.0, 0);
201
202 let m = Millis(10) + Millis(20);
203 assert_eq!(m.0, 30);
204
205 let m = Millis(10) + Millis(u32::MAX);
206 assert_eq!(m.0, u32::MAX);
207
208 let m = Millis(10) + Seconds(1);
209 assert_eq!(m.0, 1010);
210
211 let m = Millis(u32::MAX) + Seconds(1);
212 assert_eq!(m.0, u32::MAX);
213
214 let m = Millis(10) + Duration::from_millis(100);
215 assert_eq!(m.0, 110);
216
217 let m = Duration::from_millis(100) + Millis(10);
218 assert_eq!(m, Duration::from_millis(110));
219
220 let m = Millis::from(Seconds(1));
221 assert_eq!(m.0, 1000);
222
223 let m = Millis::from(Duration::from_secs(1));
224 assert_eq!(m.0, 1000);
225
226 let m = Millis::from(Duration::from_secs(u64::MAX));
227 assert_eq!(m.0, 2_147_483_648);
228
229 let m = Millis::from_secs(1);
230 assert_eq!(m.0, 1000);
231
232 let m = Millis(0);
233 assert_eq!(m.map(|m| m + Millis(1)), None);
234
235 let m = Millis(1);
236 assert_eq!(m.map(|m| m + Millis(1)), Some(Millis(2)));
237
238 let s = Seconds::new(10);
239 assert_eq!(s.0, 10);
240
241 let s = Seconds::checked_new(10);
242 assert_eq!(s.0, 10);
243
244 let s = Seconds::checked_new(u16::MAX as usize + 10);
245 assert_eq!(s.0, u16::MAX);
246
247 assert!(Seconds::ZERO.is_zero());
248 assert!(!Seconds::ZERO.non_zero());
249
250 let s = Seconds::new(10);
251 assert_eq!(s.seconds(), 10);
252
253 let s = Seconds::default();
254 assert_eq!(s.0, 0);
255
256 let s = Seconds::new(10) + Seconds::new(10);
257 assert_eq!(s.seconds(), 20);
258
259 assert_eq!(Seconds(0).map(|_| 1usize), None);
260 assert_eq!(Seconds(2).map(|_| 1usize), Some(1));
261
262 let d = Duration::from(Seconds(100));
263 assert_eq!(d.as_secs(), 100);
264 }
265}