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