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 {
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/// A Seconds type to represent a span of time in seconds.
115#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
116pub struct Seconds(pub u16);
117
118impl Seconds {
119    /// Zero seconds value
120    pub const ZERO: Seconds = Seconds(0);
121
122    /// One second value
123    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    /// Call function `f` if seconds is none zero.
156    #[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}