moq_net/runtime.rs
1//! Private deadlines driven by the owning driver's supplied clock.
2
3use std::task::Poll;
4
5/// The instant type used for deadlines and annotations.
6///
7/// [`std::time::Instant`] on native. The browser has no monotonic std clock, so
8/// wasm substitutes an equivalent backed by `performance.now()`.
9#[cfg(not(target_family = "wasm"))]
10pub type Instant = std::time::Instant;
11/// The instant type used for deadlines and annotations (wasm shim).
12#[cfg(target_family = "wasm")]
13pub type Instant = web_async::time::Instant;
14
15/// A single re-armable timer registration, produced by [`Timers::timer`].
16///
17/// This is the primitive [`Deadline`] wraps; implement it, use `Deadline`.
18/// Arming is synchronous and in-memory: no I/O submission, no async
19/// cancellation. Implementations typically keep a slot in the runtime's timer
20/// wheel (or wrap a tokio `Sleep`).
21pub trait Timer {
22 /// Arm, re-arm, or disarm (`None`) the timer.
23 ///
24 /// Re-arming an elapsed timer for a later instant makes it pend again;
25 /// re-arming for an instant already in the past leaves it elapsed.
26 fn set(&mut self, at: Option<Instant>);
27
28 /// Ready once the armed instant has passed, registering `waiter` otherwise.
29 ///
30 /// Fused: an elapsed timer keeps reporting `Ready` until re-armed. A
31 /// disarmed timer never fires.
32 fn poll(&mut self, waiter: &kio::Waiter) -> Poll<()>;
33}
34
35/// The timer half of a runtime: mint [`Timer`]s and read the clock they follow.
36///
37/// Shared by session and origin drivers, independently of their transport or
38/// executor. Clones must be cheap (a ZST or a reference count).
39pub trait Timers: Clone {
40 /// The timer registration this runtime hands out.
41 type Timer: Timer;
42
43 /// A new, disarmed timer.
44 fn timer(&self) -> Self::Timer;
45
46 /// The latest instant supplied by the owner.
47 fn now(&self) -> Instant;
48}
49
50/// A wall-clock deadline: the ergonomic layer over [`Timer`].
51///
52/// Arm it with an [`Instant`], poll it from a `poll_*` function, re-arm or
53/// disarm as the deadline moves. Re-setting the instant it already holds does
54/// nothing, so a poll loop can recompute its deadline every turn without
55/// restarting the countdown.
56pub struct Deadline<R: Timers> {
57 at: Option<Instant>,
58 timer: R::Timer,
59}
60
61impl<R: Timers> Deadline<R> {
62 /// A disarmed deadline, which never fires until [`set`](Self::set) arms it.
63 pub fn new(runtime: &R) -> Self {
64 Self {
65 at: None,
66 timer: runtime.timer(),
67 }
68 }
69
70 /// A deadline armed for `at`.
71 pub fn at(runtime: &R, at: Instant) -> Self {
72 let mut deadline = Self::new(runtime);
73 deadline.set(Some(at));
74 deadline
75 }
76
77 /// A deadline armed for `duration` past the runtime's [`now`](Timers::now).
78 ///
79 /// A duration the clock cannot represent (e.g. [`std::time::Duration::MAX`])
80 /// leaves the deadline disarmed, so it never fires rather than panicking on
81 /// the overflow.
82 pub fn after(runtime: &R, duration: std::time::Duration) -> Self {
83 let mut deadline = Self::new(runtime);
84 deadline.set(runtime.now().checked_add(duration));
85 deadline
86 }
87
88 /// Arm, re-arm, or disarm (`None`) the deadline.
89 pub fn set(&mut self, at: Option<Instant>) {
90 if self.at == at {
91 return;
92 }
93 self.at = at;
94 self.timer.set(at);
95 }
96
97 /// The instant this fires at, or `None` while disarmed.
98 pub fn deadline(&self) -> Option<Instant> {
99 self.at
100 }
101
102 /// Poll the deadline, registering `waiter` so the poll re-fires once it
103 /// elapses. `Ready` once the instant has passed, `Pending` before then and
104 /// while disarmed.
105 pub fn poll(&mut self, waiter: &kio::Waiter) -> Poll<()> {
106 if self.at.is_none() {
107 return Poll::Pending;
108 }
109 self.timer.poll(waiter)
110 }
111}
112
113impl<R: Timers> std::fmt::Debug for Deadline<R> {
114 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
115 f.debug_struct("Deadline").field("at", &self.at).finish()
116 }
117}
118
119#[cfg(test)]
120mod test;
121#[cfg(test)]
122pub use test::Test;
123
124/// A tokio-backed runtime for this crate's own unit tests, so the existing
125/// `tokio::time::pause`/`advance` tests keep their semantics: `now` reads
126/// tokio's (pausable) clock and timers are tokio sleeps, which paused tests
127/// auto-advance. Production adapters live outside this crate; this one is
128/// compiled only into the test harness (integration tests carry their own copy
129/// in `tests/support`).
130#[cfg(all(test, not(target_family = "wasm")))]
131pub(crate) mod tokio_test {
132 use std::{pin::Pin, task::Poll};
133
134 use super::{Instant, Timer};
135
136 #[derive(Clone, Default)]
137 pub(crate) struct Tokio;
138
139 impl Tokio {
140 pub fn new() -> Self {
141 Self
142 }
143 }
144
145 impl super::Timers for Tokio {
146 type Timer = TokioTimer;
147
148 fn timer(&self) -> Self::Timer {
149 TokioTimer { at: None, sleep: None }
150 }
151
152 fn now(&self) -> Instant {
153 tokio::time::Instant::now().into_std()
154 }
155 }
156
157 pub(crate) struct TokioTimer {
158 at: Option<Instant>,
159 // Allocated on the first poll after arming, then re-armed in place via
160 // `Sleep::reset`. Construction is deferred because it panics without a
161 // live tokio time driver, and only the poll is guaranteed to run inside
162 // the runtime.
163 sleep: Option<Pin<Box<tokio::time::Sleep>>>,
164 }
165
166 impl Timer for TokioTimer {
167 fn set(&mut self, at: Option<Instant>) {
168 self.at = at;
169 // Reuse the allocation when there is one; `reset` also clears
170 // `is_elapsed`.
171 if let (Some(at), Some(sleep)) = (at, &mut self.sleep) {
172 sleep.as_mut().reset(tokio::time::Instant::from_std(at));
173 }
174 }
175
176 fn poll(&mut self, waiter: &kio::Waiter) -> Poll<()> {
177 let Some(at) = self.at else { return Poll::Pending };
178 let sleep = self
179 .sleep
180 .get_or_insert_with(|| Box::pin(tokio::time::sleep_until(tokio::time::Instant::from_std(at))));
181 if sleep.is_elapsed() {
182 return Poll::Ready(());
183 }
184 waiter.poll_future(sleep.as_mut())
185 }
186 }
187}