Skip to main content

ureq/unversioned/transport/
time.rs

1//! Internal time wrappers
2
3use std::cmp::Ordering;
4use std::ops::{Add, Deref, Div};
5use std::time;
6
7/// Wrapper for [`std::time::Instant`] that provides additional time points in the past or future
8#[derive(Debug, Clone, Copy, PartialEq, Eq)]
9pub enum Instant {
10    /// A time in the past that already happened.
11    AlreadyHappened,
12    /// An exact instant.
13    Exact(time::Instant),
14    /// A time in the future that will never happen.
15    NotHappening,
16}
17
18/// Wrapper for [`std::time::Duration`] that provides a duration to a distant future
19#[derive(Debug, Clone, Copy, PartialEq, Eq)]
20pub enum Duration {
21    /// An exact duration.
22    Exact(time::Duration),
23    /// A duration so long it will never happen.
24    NotHappening,
25}
26
27impl Duration {
28    const ZERO: Duration = Duration::Exact(time::Duration::ZERO);
29
30    /// Creates a duration from seconds.
31    pub const fn from_secs(secs: u64) -> Duration {
32        Duration::Exact(time::Duration::from_secs(secs))
33    }
34
35    /// Creates a duration from milliseconds.
36    pub const fn from_millis(millis: u64) -> Duration {
37        Duration::Exact(time::Duration::from_millis(millis))
38    }
39
40    /// Tells if this duration will ever happen.
41    pub fn is_not_happening(&self) -> bool {
42        *self == Duration::NotHappening
43    }
44}
45
46const NOT_HAPPENING: time::Duration = time::Duration::from_secs(u64::MAX);
47
48impl Deref for Duration {
49    type Target = time::Duration;
50
51    fn deref(&self) -> &Self::Target {
52        match self {
53            Duration::Exact(v) => v,
54            Duration::NotHappening => &NOT_HAPPENING,
55        }
56    }
57}
58
59impl Instant {
60    /// Current time.
61    pub fn now() -> Self {
62        Instant::Exact(time::Instant::now())
63    }
64
65    pub(crate) fn duration_since(&self, earlier: Instant) -> Duration {
66        match (self, earlier) {
67            (Instant::AlreadyHappened, Instant::AlreadyHappened) => Duration::ZERO,
68            (Instant::AlreadyHappened, Instant::Exact(_)) => Duration::ZERO,
69            (Instant::AlreadyHappened, Instant::NotHappening) => Duration::ZERO,
70            (Instant::Exact(_), Instant::NotHappening) => Duration::ZERO,
71            (Instant::Exact(v1), Instant::Exact(v2)) => {
72                Duration::Exact(v1.saturating_duration_since(v2))
73            }
74            (Instant::Exact(_), Instant::AlreadyHappened) => Duration::NotHappening,
75            (Instant::NotHappening, Instant::AlreadyHappened) => Duration::NotHappening,
76            (Instant::NotHappening, Instant::Exact(_)) => Duration::NotHappening,
77            (Instant::NotHappening, Instant::NotHappening) => Duration::NotHappening,
78        }
79    }
80}
81
82impl Add<Duration> for Instant {
83    type Output = Instant;
84
85    fn add(self, rhs: Duration) -> Self::Output {
86        match (self, rhs) {
87            (Instant::AlreadyHappened, Duration::Exact(_)) => Instant::AlreadyHappened,
88            (Instant::AlreadyHappened, Duration::NotHappening) => Instant::AlreadyHappened,
89            (Instant::Exact(v1), Duration::Exact(v2)) => Instant::Exact(v1.add(v2)),
90            (Instant::Exact(_), Duration::NotHappening) => Instant::NotHappening,
91            (Instant::NotHappening, Duration::Exact(_)) => Instant::NotHappening,
92            (Instant::NotHappening, Duration::NotHappening) => Instant::NotHappening,
93        }
94    }
95}
96
97impl Div<u32> for Duration {
98    type Output = Duration;
99
100    fn div(self, rhs: u32) -> Self::Output {
101        match self {
102            Duration::Exact(d) => Duration::Exact(d / rhs),
103            Duration::NotHappening => Duration::NotHappening,
104        }
105    }
106}
107
108impl PartialOrd for Instant {
109    fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
110        Some(Self::cmp(self, other))
111    }
112}
113
114impl Ord for Instant {
115    fn cmp(&self, other: &Self) -> Ordering {
116        match (self, other) {
117            (Instant::AlreadyHappened, Instant::AlreadyHappened) => Ordering::Equal,
118            (Instant::AlreadyHappened, Instant::Exact(_)) => Ordering::Less,
119            (Instant::AlreadyHappened, Instant::NotHappening) => Ordering::Less,
120            (Instant::Exact(_), Instant::AlreadyHappened) => Ordering::Greater,
121            (Instant::Exact(v1), Instant::Exact(v2)) => v1.cmp(v2),
122            (Instant::Exact(_), Instant::NotHappening) => Ordering::Less,
123            (Instant::NotHappening, Instant::AlreadyHappened) => Ordering::Greater,
124            (Instant::NotHappening, Instant::Exact(_)) => Ordering::Greater,
125            (Instant::NotHappening, Instant::NotHappening) => Ordering::Equal,
126        }
127    }
128}
129
130impl PartialOrd for Duration {
131    fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
132        Some(Self::cmp(self, other))
133    }
134}
135
136impl Ord for Duration {
137    fn cmp(&self, other: &Self) -> Ordering {
138        match (self, other) {
139            (Duration::Exact(v1), Duration::Exact(v2)) => v1.cmp(v2),
140            (Duration::Exact(_), Duration::NotHappening) => Ordering::Less,
141            (Duration::NotHappening, Duration::Exact(_)) => Ordering::Greater,
142            (Duration::NotHappening, Duration::NotHappening) => Ordering::Equal,
143        }
144    }
145}
146
147impl From<std::time::Duration> for Duration {
148    fn from(value: std::time::Duration) -> Self {
149        Self::Exact(value)
150    }
151}
152
153#[cfg(test)]
154mod test {
155    use super::*;
156
157    #[test]
158    fn time_ord() {
159        assert!(Instant::AlreadyHappened < Instant::now());
160        assert!(Instant::now() < Instant::NotHappening);
161        assert!(Instant::AlreadyHappened < Instant::NotHappening);
162    }
163}