Skip to main content

react_rs_core/
runtime.rs

1use std::cell::RefCell;
2use std::collections::VecDeque;
3
4thread_local! {
5    pub static RUNTIME: RefCell<Runtime> = RefCell::new(Runtime::new());
6}
7
8type EffectId = usize;
9type EffectFn = Box<dyn Fn()>;
10
11pub struct Runtime {
12    effects: Vec<Option<EffectFn>>,
13    current_effect: Option<EffectId>,
14    pending_effects: VecDeque<EffectId>,
15    is_batching: bool,
16}
17
18impl Runtime {
19    pub fn new() -> Self {
20        Self {
21            effects: Vec::new(),
22            current_effect: None,
23            pending_effects: VecDeque::new(),
24            is_batching: false,
25        }
26    }
27
28    pub fn current_effect(&self) -> Option<EffectId> {
29        self.current_effect
30    }
31
32    pub fn register_effect(&mut self, f: impl Fn() + 'static) -> EffectId {
33        let id = self.effects.len();
34        self.effects.push(Some(Box::new(f)));
35        id
36    }
37
38    pub fn set_current_effect(&mut self, id: Option<EffectId>) -> Option<EffectId> {
39        let prev = self.current_effect;
40        self.current_effect = id;
41        prev
42    }
43
44    pub fn get_effect(&self, id: EffectId) -> Option<&EffectFn> {
45        self.effects.get(id).and_then(|e| e.as_ref())
46    }
47
48    pub fn schedule_effect(&mut self, id: EffectId) {
49        if !self.pending_effects.contains(&id) {
50            self.pending_effects.push_back(id);
51        }
52    }
53
54    pub fn is_batching(&self) -> bool {
55        self.is_batching
56    }
57
58    pub fn pop_pending_effect(&mut self) -> Option<EffectId> {
59        self.pending_effects.pop_front()
60    }
61
62    pub fn start_batch(&mut self) -> bool {
63        let was_batching = self.is_batching;
64        self.is_batching = true;
65        was_batching
66    }
67
68    pub fn end_batch(&mut self, was_batching: bool) {
69        self.is_batching = was_batching;
70    }
71}
72
73impl Default for Runtime {
74    fn default() -> Self {
75        Self::new()
76    }
77}