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