reactive_signals/runtimes/
test_client.rs

1use std::cell::RefCell;
2
3use super::{Runtime, RuntimeInner, Scope};
4
5thread_local! {
6  pub static RUNTIME_POOL: TestClientRuntimePool = Default::default();
7}
8
9/// A runtime meant to be used for testing only. It uses a pool of runtimes,
10/// so that many runtimes can co-exist on one thread, but simulates running on a client.
11///
12/// ```no_run
13/// use reactive_signals::{Scope, signal, runtimes::TestClientRuntime};
14///
15/// // when starting a client you create the root scope
16/// let sc = TestClientRuntime::new_root_scope();
17///
18/// // this scope is then used for building a tree of scopes.
19/// app(sc);
20///
21/// // calling discard() on the root scope will discard the TestClientRuntime as well.
22/// sc.discard();
23///
24/// fn app(sc: Scope<TestClientRuntime>) {
25///     // a signal marked with `server` will not run in a Scope<TestClientRuntime>
26///     let sig = signal!(sc, server, move || println!("server!"));
27/// }
28/// ```
29///
30/// See [runtimes](super) for full documentation.
31///
32#[derive(Default, Clone, Copy)]
33pub struct TestClientRuntime(u32);
34
35impl TestClientRuntime {
36    pub(crate) fn from(idx: usize) -> Self {
37        if idx >= u32::MAX as usize {
38            panic!("Too many runtimes. Check your code for leaks. A runtime needs to be discarded");
39        }
40        Self(idx as u32)
41    }
42}
43
44impl Runtime for TestClientRuntime {
45    const IS_SERVER: bool = false;
46
47    fn with_mut<F, T>(&self, f: F) -> T
48    where
49        F: FnOnce(&mut RuntimeInner<TestClientRuntime>) -> T,
50    {
51        RUNTIME_POOL.with(|pool| {
52            let mut pool = pool.0.borrow_mut();
53            let rt = &mut pool[self.0 as usize];
54            f(rt)
55        })
56    }
57
58    fn with_ref<F, T>(&self, f: F) -> T
59    where
60        F: FnOnce(&RuntimeInner<TestClientRuntime>) -> T,
61    {
62        RUNTIME_POOL.with(|pool| {
63            let pool = pool.0.borrow();
64            let rt = &pool[self.0 as usize];
65            f(rt)
66        })
67    }
68}
69
70#[derive(Default)]
71pub struct TestClientRuntimePool(RefCell<Vec<RuntimeInner<TestClientRuntime>>>);
72
73impl TestClientRuntime {
74    pub fn new_root_scope() -> Scope<TestClientRuntime> {
75        RUNTIME_POOL.with(|rt| {
76            let mut vec = rt.0.borrow_mut();
77
78            for (i, rt) in &mut vec.iter_mut().enumerate() {
79                if !rt.in_use() {
80                    let id = rt.scope_tree.init(Default::default());
81                    return Scope {
82                        rt: TestClientRuntime(i as u32),
83                        sx: id,
84                    };
85                }
86            }
87
88            let id = TestClientRuntime::from(vec.len());
89            let mut rti = RuntimeInner::new();
90            rti.scope_tree.init(Default::default());
91            let sx = rti.scope_tree.root();
92            vec.push(rti);
93            Scope { rt: id, sx }
94        })
95    }
96
97    #[cfg(any(test, feature = "profile"))]
98    pub fn bench_root_scope() -> Scope<TestClientRuntime> {
99        RUNTIME_POOL.with(|rt| {
100            drop(rt.0.borrow_mut().clear());
101            Self::new_root_scope()
102        })
103    }
104}