1use std::time::{Duration, Instant};
2
3#[derive(Debug)]
4pub enum Deadline {
5 Point(Instant),
6 Forever,
7 Uninitialized(Duration),
8 Elapsed,
9}
10
11impl Deadline {
12 #[inline(always)]
13 pub fn lazy_after(duration: Duration) -> Self {
14 Self::Uninitialized(duration)
15 }
16
17 #[inline(always)]
18 pub fn after(duration: Duration) -> Self {
19 let mut deadline = Self::lazy_after(duration);
20 deadline.ensure_initialized();
21 deadline
22 }
23
24 #[inline(always)]
25 fn saturating_add(instant: Instant, duration: Duration) -> Self {
26 match instant.checked_add(duration) {
27 None => Deadline::Forever,
28 Some(instant) => Deadline::Point(instant),
29 }
30 }
31
32 #[inline(always)]
33 fn ensure_initialized(&mut self) {
34 if let Self::Uninitialized(duration) = self {
35 if duration == &Duration::MAX {
36 *self = Deadline::Forever;
37 } else if duration == &Duration::ZERO {
38 *self = Deadline::Elapsed;
39 } else {
40 *self = Self::saturating_add(Instant::now(), *duration);
41 }
42 }
43 }
44
45 #[inline(always)]
46 pub fn remaining(&mut self) -> Duration {
47 self.ensure_initialized();
48
49 match self {
50 Deadline::Point(instant) => *instant - Instant::now(),
51 Deadline::Forever => Duration::MAX,
52 Deadline::Elapsed => Duration::ZERO,
53 _ => unreachable!(),
54 }
55 }
56}