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