1#![cfg_attr(not(debug_assertions), deny(clippy::disallowed_methods))]
10#![cfg_attr(debug_assertions, warn(clippy::disallowed_methods))]
11#![allow(clippy::tabs_in_doc_comments)]
12#![allow(dead_code)]
13
14pub mod cache;
15
16pub mod context;
17
18pub mod fatal;
19
20pub mod pool;
21
22pub mod shutdown;
23
24pub mod sync;
25
26pub mod actor;
27
28pub mod version_epoch;
29
30#[cfg(reifydb_dst)]
31pub mod testing;
32
33#[cfg(not(reifydb_dst))]
34use std::future::Future;
35
36use crate::{
37 actor::system::ActorSystem,
38 context::clock::{Clock, MockClock},
39 pool::{PoolConfig, Pools},
40 shutdown::Shutdown,
41};
42
43#[derive(Clone)]
44pub struct RuntimeConfig {
45 pub clock: Clock,
46 pub rng: context::rng::Rng,
47 pub fatal: fatal::FatalConfig,
48}
49
50impl Default for RuntimeConfig {
51 fn default() -> Self {
52 Self {
53 clock: Clock::Real,
54 rng: context::rng::Rng::default(),
55 fatal: fatal::FatalConfig::default(),
56 }
57 }
58}
59
60impl RuntimeConfig {
61 pub fn seeded(mut self, seed: u64) -> Self {
62 self.clock = Clock::Mock(MockClock::from_millis(seed));
63 self.rng = context::rng::Rng::seeded(seed);
64 self
65 }
66
67 pub fn fatal(mut self, config: fatal::FatalConfig) -> Self {
68 self.fatal = config;
69 self
70 }
71}
72
73use std::fmt;
74#[cfg(target_arch = "wasm32")]
75use std::{
76 pin::Pin,
77 task::{Context, Poll},
78};
79
80#[cfg(target_arch = "wasm32")]
81use futures_util::future::LocalBoxFuture;
82#[cfg(all(reifydb_target = "host", not(reifydb_dst)))]
83use tokio::runtime as tokio_runtime;
84#[cfg(all(reifydb_target = "host", not(reifydb_dst)))]
85use tokio::task::JoinHandle;
86
87#[cfg(target_arch = "wasm32")]
88#[derive(Clone, Copy, Debug)]
89pub struct WasmHandle;
90
91#[cfg(target_arch = "wasm32")]
92pub struct WasmJoinHandle<T> {
93 future: LocalBoxFuture<'static, T>,
94}
95
96#[cfg(target_arch = "wasm32")]
97impl<T> Future for WasmJoinHandle<T> {
98 type Output = Result<T, WasmJoinError>;
99
100 fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
101 match self.future.as_mut().poll(cx) {
102 Poll::Ready(v) => Poll::Ready(Ok(v)),
103 Poll::Pending => Poll::Pending,
104 }
105 }
106}
107
108#[cfg(target_arch = "wasm32")]
109#[derive(Debug)]
110pub struct WasmJoinError;
111
112#[cfg(target_arch = "wasm32")]
113impl fmt::Display for WasmJoinError {
114 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
115 write!(f, "WASM task failed")
116 }
117}
118
119#[cfg(target_arch = "wasm32")]
120use std::error::Error;
121
122#[cfg(target_arch = "wasm32")]
123impl Error for WasmJoinError {}
124
125use crate::actor::system::ActorSpawner;
126
127pub struct Runtime {
128 system: ActorSystem,
129 pools: Pools,
130 clock: Clock,
131 rng: context::rng::Rng,
132}
133
134impl Runtime {
135 pub fn from_config(config: RuntimeConfig, pools: PoolConfig) -> Self {
136 let pools = Pools::new(pools);
137 let system = ActorSystem::new(pools.clone(), config.clock.clone());
138
139 Self {
140 system,
141 pools,
142 clock: config.clock,
143 rng: config.rng,
144 }
145 }
146
147 pub fn handle(&self) -> RuntimeHandle {
148 RuntimeHandle {
149 system: self.system.clone(),
150 pools: self.pools.clone(),
151 clock: self.clock.clone(),
152 rng: self.rng.clone(),
153 }
154 }
155
156 pub fn actor_system(&self) -> ActorSystem {
157 self.system.clone()
158 }
159
160 pub fn spawner(&self) -> ActorSpawner {
161 self.system.spawner()
162 }
163
164 pub fn clock(&self) -> &Clock {
165 &self.clock
166 }
167
168 pub fn rng(&self) -> &context::rng::Rng {
169 &self.rng
170 }
171
172 #[cfg(all(reifydb_target = "host", not(reifydb_dst)))]
173 pub fn tokio(&self) -> tokio_runtime::Handle {
174 self.pools.handle()
175 }
176
177 #[cfg(target_arch = "wasm32")]
178 pub fn tokio(&self) -> WasmHandle {
179 WasmHandle
180 }
181
182 #[cfg(all(reifydb_target = "host", not(reifydb_dst)))]
183 pub fn spawn<F>(&self, future: F) -> JoinHandle<F::Output>
184 where
185 F: Future + Send + 'static,
186 F::Output: Send + 'static,
187 {
188 self.pools.spawn(future)
189 }
190
191 #[cfg(target_arch = "wasm32")]
192 pub fn spawn<F>(&self, future: F) -> WasmJoinHandle<F::Output>
193 where
194 F: Future + 'static,
195 F::Output: 'static,
196 {
197 WasmJoinHandle {
198 future: Box::pin(future),
199 }
200 }
201
202 #[cfg(all(reifydb_target = "host", not(reifydb_dst)))]
203 pub fn block_on<F>(&self, future: F) -> F::Output
204 where
205 F: Future,
206 {
207 self.pools.block_on(future)
208 }
209
210 #[cfg(target_arch = "wasm32")]
211 pub fn block_on<F>(&self, _future: F) -> F::Output
212 where
213 F: Future,
214 {
215 unimplemented!("block_on not supported in WASM - use async execution instead")
216 }
217}
218
219impl Shutdown for Runtime {
220 fn shutdown(&self) {
221 self.system.shutdown();
222 let _ = self.system.join();
223 self.pools.shutdown();
224 }
225}
226
227impl Drop for Runtime {
228 fn drop(&mut self) {
229 self.shutdown();
230 }
231}
232
233impl fmt::Debug for Runtime {
234 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
235 f.debug_struct("Runtime").finish_non_exhaustive()
236 }
237}
238
239#[derive(Clone)]
240pub struct RuntimeHandle {
241 system: ActorSystem,
242 pools: Pools,
243 clock: Clock,
244 rng: context::rng::Rng,
245}
246
247impl RuntimeHandle {
248 pub fn actor_system(&self) -> ActorSystem {
249 self.system.clone()
250 }
251
252 pub fn spawner(&self) -> ActorSpawner {
253 self.system.spawner()
254 }
255
256 pub fn pools(&self) -> Pools {
257 self.pools.clone()
258 }
259
260 pub fn clock(&self) -> &Clock {
261 &self.clock
262 }
263
264 pub fn rng(&self) -> &context::rng::Rng {
265 &self.rng
266 }
267
268 #[cfg(all(reifydb_target = "host", not(reifydb_dst)))]
269 pub fn tokio(&self) -> tokio_runtime::Handle {
270 self.pools.handle()
271 }
272
273 #[cfg(target_arch = "wasm32")]
274 pub fn tokio(&self) -> WasmHandle {
275 WasmHandle
276 }
277
278 #[cfg(all(reifydb_target = "host", not(reifydb_dst)))]
279 pub fn spawn<F>(&self, future: F) -> JoinHandle<F::Output>
280 where
281 F: Future + Send + 'static,
282 F::Output: Send + 'static,
283 {
284 self.pools.spawn(future)
285 }
286
287 #[cfg(target_arch = "wasm32")]
288 pub fn spawn<F>(&self, future: F) -> WasmJoinHandle<F::Output>
289 where
290 F: Future + 'static,
291 F::Output: 'static,
292 {
293 WasmJoinHandle {
294 future: Box::pin(future),
295 }
296 }
297
298 #[cfg(all(reifydb_target = "host", not(reifydb_dst)))]
299 pub fn block_on<F>(&self, future: F) -> F::Output
300 where
301 F: Future,
302 {
303 self.pools.block_on(future)
304 }
305
306 #[cfg(target_arch = "wasm32")]
307 pub fn block_on<F>(&self, _future: F) -> F::Output
308 where
309 F: Future,
310 {
311 unimplemented!("block_on not supported in WASM - use async execution instead")
312 }
313}
314
315impl fmt::Debug for RuntimeHandle {
316 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
317 f.debug_struct("RuntimeHandle").finish_non_exhaustive()
318 }
319}
320
321#[cfg(all(test, not(reifydb_single_threaded)))]
322mod tests {
323 use super::*;
324
325 fn test_config() -> RuntimeConfig {
326 RuntimeConfig::default()
327 }
328
329 fn test_pools() -> PoolConfig {
330 PoolConfig {
331 coordination_threads: 2,
332 flow_threads: 2,
333 maintenance_threads: 1,
334 task_threads: 2,
335 compute_threads: 2,
336 async_threads: 2,
337 }
338 }
339
340 #[test]
341 fn test_runtime_creation() {
342 let runtime = Runtime::from_config(test_config(), test_pools());
343 let result = runtime.block_on(async { 42 });
344 assert_eq!(result, 42);
345 }
346
347 #[test]
348 fn test_spawn() {
349 let runtime = Runtime::from_config(test_config(), test_pools());
350 let handle = runtime.spawn(async { 123 });
351 let result = runtime.block_on(handle).unwrap();
352 assert_eq!(result, 123);
353 }
354
355 #[test]
356 fn test_actor_system_accessible() {
357 let runtime = Runtime::from_config(test_config(), test_pools());
358 let _system = runtime.actor_system();
359 }
360
361 #[test]
362 fn test_shutdown_drops_runtime() {
363 let runtime = Runtime::from_config(test_config(), test_pools());
364 let spawner = runtime.spawner();
365 assert!(spawner.is_alive());
366 drop(runtime);
367 assert!(!spawner.is_alive());
368 }
369}