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
use std::{
collections::BinaryHeap,
task::Waker,
time::{Duration, Instant},
};
pub(crate) struct Sleeper {
pub deadline: Instant,
pub waker: Waker,
}
impl PartialEq for Sleeper {
fn eq(&self, other: &Self) -> bool {
self.deadline.eq(&other.deadline)
}
}
impl PartialOrd for Sleeper {
fn partial_cmp(&self, other: &Self) -> Option<core::cmp::Ordering> {
Some(self.cmp(other))
}
}
impl Eq for Sleeper {}
impl Ord for Sleeper {
fn cmp(&self, other: &Self) -> core::cmp::Ordering {
// NOTE: Sleeper with the earliest deadline (minimum `Instant` ordering) must have the
// highest priority in the queue.
self.deadline.cmp(&other.deadline).reverse()
}
}
pub struct Reactor {
pub(crate) sleepers: BinaryHeap<Sleeper>,
}
impl Reactor {
pub const fn new() -> Self {
Self {
sleepers: BinaryHeap::new(),
}
}
/// Queues any sleepers ready to wake. Returns the time until a sleeper will awaken, or zero if
/// one is ready.
pub fn tick(&mut self) -> Duration {
let now = Instant::now();
let mut min_ttw = Duration::MAX;
while let Some(next) = self.sleepers.peek() {
let time_to_wake = next.deadline.saturating_duration_since(now);
if time_to_wake < min_ttw {
min_ttw = time_to_wake;
}
if time_to_wake.is_zero() {
// We want to wake all of the expired sleepers, so don't stop early.
let sleeper = self.sleepers.pop().unwrap();
sleeper.waker.wake();
} else {
// Since we've popped all the expired sleepers, we now just care about how long we
// have to wait until the next one. The queue is drained in order,
// so we surely have encountered the smallest TTW in the list already.
break;
}
}
min_ttw
}
}