Skip to main content

loom_rs/
context.rs

1//! Thread-local runtime context.
2//!
3//! This module provides thread-local storage for accessing the current loom runtime
4//! from any thread managed by the runtime. This enables ergonomic access to runtime
5//! methods without passing the runtime reference explicitly.
6//!
7//! # Example
8//!
9//! ```ignore
10//! use loom_rs::LoomBuilder;
11//!
12//! let runtime = LoomBuilder::new().build()?;
13//!
14//! runtime.block_on(async {
15//!     // Works anywhere in the runtime's threads
16//!     let result = loom_rs::spawn_compute(|| {
17//!         expensive_work()
18//!     }).await;
19//! });
20//! ```
21
22use std::cell::RefCell;
23use std::sync::{Arc, Weak};
24
25use crate::runtime::LoomRuntimeInner;
26
27thread_local! {
28    static CURRENT_RUNTIME: RefCell<Option<Weak<LoomRuntimeInner>>> = const { RefCell::new(None) };
29}
30
31/// Get the current loom runtime from thread-local storage.
32///
33/// Returns `Some` when called from a thread managed by a `LoomRuntime`
34/// (tokio workers, rayon workers, or within `block_on`).
35///
36/// Returns `None` when called from outside a loom runtime context.
37///
38/// # Example
39///
40/// ```ignore
41/// runtime.block_on(async {
42///     // Works anywhere in the runtime's threads
43///     let rt = loom_rs::current_runtime().unwrap();
44///     rt.spawn_compute(|| work()).await;
45/// });
46/// ```
47pub fn current_runtime() -> Option<Arc<LoomRuntimeInner>> {
48    CURRENT_RUNTIME.with(|rt| rt.borrow().as_ref().and_then(|weak| weak.upgrade()))
49}
50
51/// Set the current runtime for this thread.
52///
53/// This is called internally by the runtime when starting tokio and rayon threads.
54pub(crate) fn set_current_runtime(runtime: Weak<LoomRuntimeInner>) {
55    CURRENT_RUNTIME.with(|rt| {
56        *rt.borrow_mut() = Some(runtime);
57    });
58}
59
60/// Clear the current runtime for this thread.
61///
62/// This is called internally by the runtime when threads are stopping.
63pub(crate) fn clear_current_runtime() {
64    CURRENT_RUNTIME.with(|rt| {
65        *rt.borrow_mut() = None;
66    });
67}
68
69#[cfg(test)]
70mod tests {
71    use super::*;
72
73    #[test]
74    fn test_current_runtime_none_initially() {
75        // Should be None when not in a runtime context
76        assert!(current_runtime().is_none());
77    }
78
79    #[test]
80    fn test_set_and_clear_runtime() {
81        // Create a dummy inner runtime for testing
82        // We can't easily test this without a real runtime, so just test the API
83        assert!(current_runtime().is_none());
84
85        // After clear, should still be None
86        clear_current_runtime();
87        assert!(current_runtime().is_none());
88    }
89}