ntex_util/time/
types.rs

1use std::ops;
2
3/// A Duration type to represent a span of time.
4///
5/// This type is designed for timeouts. Milliseconds resolution
6/// is too small to keep generic time.
7#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
8pub struct Millis(pub u32);
9
10impl Millis {
11    /// Zero milliseconds value
12    pub const ZERO: Millis = Millis(0);
13
14    /// One second value
15    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    /// Call function `f` if duration is none zero.
33    #[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(self.0.saturating_add((other.0 as u32).saturating_mul(1000)))
65    }
66}
67
68impl ops::Add<std::time::Duration> for Millis {
69    type Output = Millis;
70
71    #[inline]
72    fn add(self, other: std::time::Duration) -> Millis {
73        self + Millis::from(other)
74    }
75}
76
77impl ops::Add<Millis> for std::time::Duration {
78    type Output = std::time::Duration;
79
80    #[inline]
81    fn add(self, other: Millis) -> std::time::Duration {
82        self + Self::from(other)
83    }
84}
85
86impl From<u32> for Millis {
87    #[inline]
88    fn from(s: u32) -> Millis {
89        Millis(s)
90    }
91}
92
93impl From<i32> for Millis {
94    #[inline]
95    fn from(i: i32) -> Millis {
96        Millis(if i < 0 { 0 } else { i as u32 })
97    }
98}
99
100impl From<usize> for Millis {
101    #[inline]
102    fn from(s: usize) -> Millis {
103        Self(s.try_into().unwrap_or_else(|_| {
104            log::error!("Values is too large {s:?}");
105            u32::MAX
106        }))
107    }
108}
109
110impl From<Seconds> for Millis {
111    #[inline]
112    fn from(s: Seconds) -> Millis {
113        Millis((s.0 as u32).saturating_mul(1000))
114    }
115}
116
117impl From<std::time::Duration> for Millis {
118    #[inline]
119    fn from(d: std::time::Duration) -> Millis {
120        Self(d.as_millis().try_into().unwrap_or_else(|_| {
121            log::error!("time Duration is too large {d:?}");
122            1 << 31
123        }))
124    }
125}
126
127impl From<Millis> for std::time::Duration {
128    #[inline]
129    fn from(d: Millis) -> std::time::Duration {
130        std::time::Duration::from_millis(d.0 as u64)
131    }
132}
133
134/// A Seconds type to represent a span of time in seconds.
135#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
136pub struct Seconds(pub u16);
137
138impl Seconds {
139    /// Zero seconds value
140    pub const ZERO: Seconds = Seconds(0);
141
142    /// One second value
143    pub const ONE: Seconds = Seconds(1);
144
145    #[inline]
146    pub const fn new(secs: u16) -> Seconds {
147        Seconds(secs)
148    }
149
150    #[inline]
151    pub const fn checked_new(secs: usize) -> Seconds {
152        let secs = if (u16::MAX as usize) < secs {
153            u16::MAX
154        } else {
155            secs as u16
156        };
157        Seconds(secs)
158    }
159
160    #[inline]
161    pub const fn is_zero(self) -> bool {
162        self.0 == 0
163    }
164
165    #[inline]
166    pub const fn non_zero(self) -> bool {
167        self.0 != 0
168    }
169
170    #[inline]
171    pub const fn seconds(self) -> u64 {
172        self.0 as u64
173    }
174
175    /// Call function `f` if seconds is none zero.
176    #[inline]
177    pub fn map<F, R>(&self, f: F) -> Option<R>
178    where
179        F: FnOnce(Millis) -> R,
180    {
181        if self.0 == 0 {
182            None
183        } else {
184            Some(f(Millis::from(*self)))
185        }
186    }
187}
188
189impl Default for Seconds {
190    #[inline]
191    fn default() -> Seconds {
192        Seconds::ZERO
193    }
194}
195
196impl ops::Add<Seconds> for Seconds {
197    type Output = Seconds;
198
199    #[inline]
200    fn add(self, other: Seconds) -> Seconds {
201        Seconds(self.0.saturating_add(other.0))
202    }
203}
204
205impl From<Seconds> for std::time::Duration {
206    #[inline]
207    fn from(d: Seconds) -> std::time::Duration {
208        std::time::Duration::from_secs(d.0 as u64)
209    }
210}
211
212impl From<u16> for Seconds {
213    #[inline]
214    fn from(secs: u16) -> Seconds {
215        Self(secs)
216    }
217}
218
219impl From<i32> for Seconds {
220    #[inline]
221    fn from(i: i32) -> Seconds {
222        Seconds(if i < 0 { 0 } else { i as u16 })
223    }
224}
225
226impl From<usize> for Seconds {
227    #[inline]
228    fn from(secs: usize) -> Seconds {
229        Self(secs.try_into().unwrap_or_else(|_| {
230            log::error!("Seconds value is too large {secs:?}");
231            u16::MAX
232        }))
233    }
234}
235
236#[cfg(test)]
237mod tests {
238    use super::*;
239    use std::time::Duration;
240
241    #[test]
242    fn time_types() {
243        let m = Millis::default();
244        assert_eq!(m.0, 0);
245
246        let m = Millis(10) + Millis(20);
247        assert_eq!(m.0, 30);
248
249        let m = Millis(10) + Millis(u32::MAX);
250        assert_eq!(m.0, u32::MAX);
251
252        let m = Millis(10) + Seconds(1);
253        assert_eq!(m.0, 1010);
254
255        let m = Millis(u32::MAX) + Seconds(1);
256        assert_eq!(m.0, u32::MAX);
257
258        let m = Millis(10) + Duration::from_millis(100);
259        assert_eq!(m.0, 110);
260
261        let m = Duration::from_millis(100) + Millis(10);
262        assert_eq!(m, Duration::from_millis(110));
263
264        let m = Millis::from(Seconds(1));
265        assert_eq!(m.0, 1000);
266
267        let m = Millis::from(Duration::from_secs(1));
268        assert_eq!(m.0, 1000);
269
270        let m = Millis::from(Duration::from_secs(u64::MAX));
271        assert_eq!(m.0, 2_147_483_648);
272
273        let m = Millis::from_secs(1);
274        assert_eq!(m.0, 1000);
275
276        let m = Millis(0);
277        assert_eq!(m.map(|m| m + Millis(1)), None);
278
279        let m = Millis(1);
280        assert_eq!(m.map(|m| m + Millis(1)), Some(Millis(2)));
281
282        let s = Seconds::new(10);
283        assert_eq!(s.0, 10);
284
285        let s = Seconds::checked_new(10);
286        assert_eq!(s.0, 10);
287
288        let s = Seconds::checked_new(u16::MAX as usize + 10);
289        assert_eq!(s.0, u16::MAX);
290
291        assert!(Seconds::ZERO.is_zero());
292        assert!(!Seconds::ZERO.non_zero());
293
294        let s = Seconds::new(10);
295        assert_eq!(s.seconds(), 10);
296
297        let s = Seconds::default();
298        assert_eq!(s.0, 0);
299
300        let s = Seconds::new(10) + Seconds::new(10);
301        assert_eq!(s.seconds(), 20);
302
303        assert_eq!(Seconds(0).map(|_| 1usize), None);
304        assert_eq!(Seconds(2).map(|_| 1usize), Some(1));
305
306        let d = Duration::from(Seconds(100));
307        assert_eq!(d.as_secs(), 100);
308    }
309}