strontium_core/
runtime.rs1use 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}