1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
use core::cmp::Ordering;
use core::{fmt, ops};

#[doc(no_inline)]
pub use core::time::Duration;

/// A timestamp of some sort that can be used like [`std::time::Instant`].
///
/// Because this trait is not object-safe, it is usually used with the `Deadline` wrapper,
/// which provides higher-level Operations to avoid needing to compare two instants.
pub trait Instant: Copy + Ord + Send + Sync + fmt::Debug + 'static
where
    Self: ops::Add<Duration, Output = Self>,
    Self: ops::Sub<Duration, Output = Self>,
{
    /// Returns the current time.
    fn now() -> Self;

    /// Subtracts `other` from `self`, returning [`Duration::ZERO`] if the difference is
    /// negative.
    fn saturating_duration_since(self, other: Self) -> Duration;
}

#[cfg(any(feature = "std", test))]
impl Instant for std::time::Instant {
    #[inline]
    fn now() -> Self {
        std::time::Instant::now()
    }

    #[inline]
    fn saturating_duration_since(self, other: Self) -> Duration {
        std::time::Instant::saturating_duration_since(&self, other)
    }
}

/// Trivial implementation of [`Instant`] where everything happens in zero time.
///
/// Use this for specifying [`Deadline::Asap`] or [`Deadline::Whenever`] when no instant type
/// is available **and it's okay for all time measurements to be recorded as zero**.
#[doc(hidden)]
#[derive(Debug, Clone, Copy, Eq, Ord, PartialEq, PartialOrd)]
#[allow(clippy::exhaustive_structs)]
pub struct NoTime;

impl Instant for NoTime {
    #[inline]
    fn now() -> Self {
        Self
    }

    #[inline]
    fn saturating_duration_since(self, _: Self) -> Duration {
        Duration::ZERO
    }
}

impl ops::Add<Duration> for NoTime {
    type Output = Self;
    #[inline]
    fn add(self, _: Duration) -> Self::Output {
        NoTime
    }
}
impl ops::Sub<Duration> for NoTime {
    type Output = Self;
    #[inline]
    fn sub(self, _: Duration) -> Self::Output {
        NoTime
    }
}

/// A request regarding how much real time should be spent on a computation.
#[derive(Debug, Clone, Copy, Eq, Ord, PartialEq, PartialOrd)]
#[non_exhaustive]
pub enum Deadline<I> {
    /// Stop immediately after the minimum necessary activities.
    ///
    /// Arithmetically, this is “negative infinity”; it is less than all finite deadlines.
    Asap,
    /// Stop as close to the given time (before or after) as is feasible.
    At(I),
    /// Don't stop until all the work is done.
    ///
    /// This choice is appropriate when deterministic results are desired.
    ///
    /// Arithmetically, this is “positive infinity”; it is greater than all finite deadlines.
    Whenever,
}
impl<I: Instant> Deadline<I> {
    /// Returns the time between `start` and the deadline, or [`None`] if there is no
    /// deadline and the remaining time is unbounded.
    ///
    /// If the deadline is already past, returns `Some(Duration::ZERO)`
    ///
    /// (This does not return [`Duration::MAX`] since that would be likely to cause
    /// unintended arithmetic overflows.)
    #[inline]
    pub fn remaining_since(&self, start: I) -> Option<Duration> {
        match self {
            Deadline::Asap => Some(Duration::ZERO),
            Deadline::At(deadline) => Some(deadline.saturating_duration_since(start)),
            Deadline::Whenever => None,
        }
    }
}

impl<I: Instant> ops::Add<Duration> for Deadline<I> {
    type Output = Self;
    #[inline]
    fn add(self, rhs: Duration) -> Self::Output {
        match self {
            Deadline::Asap => Deadline::Asap,
            Deadline::At(i) => Deadline::At(i + rhs),
            Deadline::Whenever => Deadline::Whenever,
        }
    }
}
impl<I: Instant> ops::Sub<Duration> for Deadline<I> {
    type Output = Self;
    #[inline]
    fn sub(self, rhs: Duration) -> Self::Output {
        match self {
            Deadline::Asap => Deadline::Asap,
            Deadline::At(i) => Deadline::At(i - rhs),
            Deadline::Whenever => Deadline::Whenever,
        }
    }
}

// Allow comparing `Deadline` and `Instant` without wrapping.
impl<I: Instant> PartialEq<I> for Deadline<I> {
    #[mutants::skip] // trivial
    #[inline]
    fn eq(&self, other: &I) -> bool {
        self.partial_cmp(other) == Some(Ordering::Equal)
    }
}
/// Note: The reverse `PartialOrd<Deadline<I>> for I` is not permitted by the orphan rules.
impl<I: Instant> PartialOrd<I> for Deadline<I> {
    #[inline]
    fn partial_cmp(&self, other: &I) -> Option<Ordering> {
        Some(match self {
            Deadline::Asap => Ordering::Less,
            Deadline::At(i) => i.cmp(other),
            Deadline::Whenever => Ordering::Greater,
        })
    }
}

/// Convenience alias for [`Deadline`] with a dummy instant type.
///
/// Use this for specifying [`Deadline::Asap`] or [`Deadline::Whenever`] when no instant type
/// is available **and it's okay for all time measurements to be recorded as zero**.
pub type DeadlineNt = Deadline<NoTime>;

/// Convenience alias for [`Deadline`] with [`std::time::Instant`].
///
/// Use this for specifying [`Deadline::Asap`] or [`Deadline::Whenever`] when no instant type
/// is available **and it's okay for all time measurements to be recorded as zero**.
#[cfg(any(feature = "std", test))]
pub type DeadlineStd = Deadline<std::time::Instant>;

impl<I: Instant> From<I> for Deadline<I> {
    #[inline]
    fn from(value: I) -> Self {
        Self::At(value)
    }
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn deadline_ordering() {
        use std::time::Instant;
        let i = Instant::now();
        let mut deadlines = [
            Deadline::At(i + Duration::from_secs(1)),
            Deadline::Asap,
            Deadline::Whenever,
            Deadline::At(i),
        ];
        deadlines.sort();
        assert_eq!(
            deadlines,
            [
                Deadline::Asap,
                Deadline::At(i),
                Deadline::At(i + Duration::from_secs(1)),
                Deadline::Whenever,
            ]
        );
    }
}