1use std::future::Future;
9use std::pin::Pin;
10use std::sync::{Arc, Mutex};
11use std::task::{Context, Poll, Waker};
12use std::time::{Duration, SystemTime, UNIX_EPOCH};
13
14pub type BoxFuture<T> = Pin<Box<dyn Future<Output = T> + Send + 'static>>;
16
17pub trait Spawn: Send + Sync {
19 fn spawn(&self, fut: BoxFuture<()>);
21}
22
23pub trait Clock: Send + Sync {
26 fn now_ms(&self) -> i64;
28}
29
30pub trait Sleep: Send + Sync {
32 fn sleep_until(&self, at_ms: i64) -> BoxFuture<()>;
34}
35
36#[derive(Clone)]
38pub struct Shell {
39 pub spawn: Arc<dyn Spawn>,
41 pub clock: Arc<dyn Clock>,
43 pub sleep: Arc<dyn Sleep>,
45}
46
47impl std::fmt::Debug for Shell {
48 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
49 f.debug_struct("Shell")
50 .field("now_ms", &self.clock.now_ms())
51 .finish_non_exhaustive()
52 }
53}
54
55impl Shell {
56 pub fn tokio() -> Self {
59 let clock: Arc<dyn Clock> = Arc::new(SystemClock);
60 Shell {
61 spawn: Arc::new(TokioSpawn),
62 sleep: Arc::new(TokioSleep {
63 clock: clock.clone(),
64 }),
65 clock,
66 }
67 }
68
69 pub fn virtual_time(start_ms: i64) -> (Self, VirtualClock) {
72 let clock = VirtualClock::new(start_ms);
73 let shell = Shell {
74 spawn: Arc::new(TokioSpawn),
75 clock: Arc::new(clock.clone()),
76 sleep: Arc::new(clock.clone()),
77 };
78 (shell, clock)
79 }
80}
81
82#[derive(Clone, Copy, Debug, Default)]
84pub struct TokioSpawn;
85
86impl Spawn for TokioSpawn {
87 fn spawn(&self, fut: BoxFuture<()>) {
88 tokio::spawn(fut);
89 }
90}
91
92#[derive(Clone, Copy, Debug, Default)]
94pub struct SystemClock;
95
96impl Clock for SystemClock {
97 fn now_ms(&self) -> i64 {
98 SystemTime::now()
99 .duration_since(UNIX_EPOCH)
100 .map(|d| i64::try_from(d.as_millis()).unwrap_or(i64::MAX))
101 .unwrap_or(0)
102 }
103}
104
105#[derive(Clone)]
107pub struct TokioSleep {
108 clock: Arc<dyn Clock>,
109}
110
111impl TokioSleep {
112 pub fn new(clock: Arc<dyn Clock>) -> Self {
114 TokioSleep { clock }
115 }
116}
117
118impl std::fmt::Debug for TokioSleep {
119 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
120 f.debug_struct("TokioSleep").finish_non_exhaustive()
121 }
122}
123
124impl Sleep for TokioSleep {
125 fn sleep_until(&self, at_ms: i64) -> BoxFuture<()> {
126 let wait = at_ms.saturating_sub(self.clock.now_ms()).max(0);
127 Box::pin(tokio::time::sleep(Duration::from_millis(
128 u64::try_from(wait).unwrap_or(0),
129 )))
130 }
131}
132
133#[derive(Default)]
134struct VirtualInner {
135 now: i64,
136 waiters: Vec<(i64, Waker)>,
137}
138
139#[derive(Clone, Default)]
142pub struct VirtualClock {
143 inner: Arc<Mutex<VirtualInner>>,
144}
145
146impl std::fmt::Debug for VirtualClock {
147 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
148 f.debug_struct("VirtualClock")
149 .field("now", &self.now_ms())
150 .finish()
151 }
152}
153
154impl VirtualClock {
155 pub fn new(start_ms: i64) -> Self {
157 VirtualClock {
158 inner: Arc::new(Mutex::new(VirtualInner {
159 now: start_ms,
160 waiters: Vec::new(),
161 })),
162 }
163 }
164
165 fn lock(&self) -> std::sync::MutexGuard<'_, VirtualInner> {
166 self.inner
167 .lock()
168 .unwrap_or_else(std::sync::PoisonError::into_inner)
169 }
170
171 pub fn advance(&self, d: Duration) {
173 let ms = i64::try_from(d.as_millis()).unwrap_or(i64::MAX);
174 let now = self.now_ms().saturating_add(ms);
175 self.set(now);
176 }
177
178 pub fn set(&self, at_ms: i64) {
180 let due: Vec<Waker> = {
181 let mut g = self.lock();
182 g.now = g.now.max(at_ms);
183 let now = g.now;
184 let (ready, wait): (Vec<_>, Vec<_>) = g.waiters.drain(..).partition(|(t, _)| *t <= now);
185 g.waiters = wait;
186 ready.into_iter().map(|(_, w)| w).collect()
187 };
188 for w in due {
189 w.wake();
190 }
191 }
192}
193
194impl Clock for VirtualClock {
195 fn now_ms(&self) -> i64 {
196 self.lock().now
197 }
198}
199
200impl Sleep for VirtualClock {
201 fn sleep_until(&self, at_ms: i64) -> BoxFuture<()> {
202 Box::pin(VirtualSleep {
203 clock: self.clone(),
204 at: at_ms,
205 })
206 }
207}
208
209struct VirtualSleep {
210 clock: VirtualClock,
211 at: i64,
212}
213
214impl Future for VirtualSleep {
215 type Output = ();
216
217 fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<()> {
218 let mut g = self.clock.lock();
219 if g.now >= self.at {
220 Poll::Ready(())
221 } else {
222 g.waiters.push((self.at, cx.waker().clone()));
223 Poll::Pending
224 }
225 }
226}
227
228#[cfg(test)]
229mod tests {
230 use super::*;
231
232 #[test]
233 fn virtual_clock_moves_only_when_advanced() {
234 let c = VirtualClock::new(1_000);
235 assert_eq!(c.now_ms(), 1_000);
236 c.advance(Duration::from_millis(250));
237 assert_eq!(c.now_ms(), 1_250);
238 c.set(100);
239 assert_eq!(c.now_ms(), 1_250, "never backwards");
240 }
241
242 #[tokio::test]
243 async fn virtual_sleep_completes_after_advance() {
244 let c = VirtualClock::new(0);
245 let s = c.sleep_until(50);
246 let h = tokio::spawn(s);
247 tokio::task::yield_now().await;
248 assert!(!h.is_finished());
249 c.advance(Duration::from_millis(50));
250 h.await.unwrap();
251 }
252}