Skip to main content

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(
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/// A Seconds type to represent a span of time in seconds.
138#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
139pub struct Seconds(pub u16);
140
141impl Seconds {
142    /// Zero seconds value
143    pub const ZERO: Seconds = Seconds(0);
144
145    /// One second value
146    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    /// Call function `f` if seconds is none zero.
179    #[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}