Skip to main content

strontium_core/
runtime.rs

1use crate::clock::Clock;
2use crate::executor::{Reactor, TaskHandle};
3use crate::futures::Interval;
4use crate::trace::TraceBuffer;
5use std::future::Future;
6use std::pin::Pin;
7use std::sync::{Arc, Mutex};
8use std::time::{Duration, Instant};
9
10pub type RuntimeFuture = Pin<Box<dyn Future<Output = ()> + Send + Sync + 'static>>;
11pub type TaskFuture = Pin<Box<dyn Future<Output = ()> + Send + 'static>>;
12
13pub trait Runtime {
14    fn clock_ref(&self) -> &Arc<Mutex<Clock>>;
15    fn yield_now(&self) -> RuntimeFuture;
16    fn sleep(&self, duration: Duration) -> RuntimeFuture;
17    fn create_interval(&self, duration: Duration) -> Interval;
18    fn now(&self) -> Instant;
19    fn elapsed_since(&self, start: Instant) -> u64;
20    fn next_u64(&self) -> u64;
21}
22
23pub trait DeterministicControl {
24    fn spawn_local_task(&self, fut: TaskFuture) -> TaskHandle;
25    fn run_until_idle(&self);
26    fn advance_time(&self, duration: Duration);
27    fn run_to_completion(&self);
28    fn step_count(&self) -> u64;
29    fn seed(&self) -> u64;
30    fn virtual_elapsed(&self) -> Duration;
31    fn decision_log(&self) -> Vec<usize>;
32    fn set_replay_decisions(&self, decisions: Vec<usize>);
33    fn clear_decision_log(&self);
34    fn trace_snapshot(&self) -> TraceBuffer;
35}
36
37impl Runtime for Reactor {
38    fn clock_ref(&self) -> &Arc<Mutex<Clock>> {
39        Self::clock_ref(self)
40    }
41
42    fn yield_now(&self) -> RuntimeFuture {
43        Self::yield_now(self)
44    }
45
46    fn sleep(&self, duration: Duration) -> RuntimeFuture {
47        Self::sleep(self, duration)
48    }
49
50    fn create_interval(&self, duration: Duration) -> Interval {
51        Self::create_interval(self, duration)
52    }
53
54    fn now(&self) -> Instant {
55        Self::now(self)
56    }
57
58    fn elapsed_since(&self, start: Instant) -> u64 {
59        Self::elapsed_since(self, start)
60    }
61
62    fn next_u64(&self) -> u64 {
63        Self::next_u64(self)
64    }
65}
66
67impl DeterministicControl for Reactor {
68    fn spawn_local_task(&self, fut: TaskFuture) -> TaskHandle {
69        Self::spawn_local_task(self, fut)
70    }
71
72    fn run_until_idle(&self) {
73        Self::run_until_idle(self)
74    }
75
76    fn advance_time(&self, duration: Duration) {
77        Self::advance_time(self, duration)
78    }
79
80    fn run_to_completion(&self) {
81        Self::run_to_completion(self)
82    }
83
84    fn step_count(&self) -> u64 {
85        Self::step_count(self)
86    }
87
88    fn seed(&self) -> u64 {
89        Self::seed(self)
90    }
91
92    fn virtual_elapsed(&self) -> Duration {
93        Self::virtual_elapsed(self)
94    }
95
96    fn decision_log(&self) -> Vec<usize> {
97        Self::decision_log(self)
98    }
99
100    fn set_replay_decisions(&self, decisions: Vec<usize>) {
101        Self::set_replay_decisions(self, decisions)
102    }
103
104    fn clear_decision_log(&self) {
105        Self::clear_decision_log(self)
106    }
107
108    fn trace_snapshot(&self) -> TraceBuffer {
109        Self::trace_snapshot(self)
110    }
111}
112
113#[cfg(test)]
114mod tests {
115    use super::{DeterministicControl, Runtime};
116    use crate::executor::Reactor;
117    use std::task::Poll;
118    use std::time::Duration;
119
120    #[test]
121    fn reactor_implements_runtime_and_control_contracts() {
122        let reactor = Reactor::new(17);
123
124        let _clock = Runtime::clock_ref(&reactor);
125        let mut yielded = Runtime::yield_now(&reactor);
126        let _sleep = Runtime::sleep(&reactor, Duration::from_millis(1));
127        let _interval = Runtime::create_interval(&reactor, Duration::from_millis(1));
128        let start = Runtime::now(&reactor);
129        let _elapsed = Runtime::elapsed_since(&reactor, start);
130        let _random = Runtime::next_u64(&reactor);
131
132        let waker = std::task::Waker::noop();
133        let mut cx = std::task::Context::from_waker(waker);
134        assert!(matches!(yielded.as_mut().poll(&mut cx), Poll::Pending));
135
136        let _task = DeterministicControl::spawn_local_task(&reactor, Box::pin(async {}));
137        DeterministicControl::run_until_idle(&reactor);
138        DeterministicControl::advance_time(&reactor, Duration::ZERO);
139        DeterministicControl::run_to_completion(&reactor);
140        let _steps = DeterministicControl::step_count(&reactor);
141        let _seed = DeterministicControl::seed(&reactor);
142        let _virtual_elapsed = DeterministicControl::virtual_elapsed(&reactor);
143        let _decision_log = DeterministicControl::decision_log(&reactor);
144        DeterministicControl::set_replay_decisions(&reactor, vec![]);
145        DeterministicControl::clear_decision_log(&reactor);
146        let _trace = DeterministicControl::trace_snapshot(&reactor);
147    }
148}