rue_core/reactive/
context.rs1use std::cell::RefCell;
2
3thread_local! {
4 static CURRENT_EFFECT: RefCell<Option<EffectId>> = const { RefCell::new(None) };
5 static EFFECTS: RefCell<Vec<Box<dyn Fn()>>> = const { RefCell::new(Vec::new()) };
6 static TRACKING: RefCell<Vec<Vec<EffectId>>> = const { RefCell::new(Vec::new()) };
7}
8
9type EffectId = usize;
10
11pub fn run_effect(f: Box<dyn Fn()>) -> EffectId {
13 EFFECTS.with(|e| {
14 let mut effects = e.borrow_mut();
15 let id = effects.len();
16 effects.push(f);
17 id
18 })
19}
20
21pub fn track_effect(effect_id: EffectId, f: impl Fn()) {
23 let prev = CURRENT_EFFECT.with(|c| c.replace(Some(effect_id)));
25 TRACKING.with(|t| {
26 let mut tracking = t.borrow_mut();
28 while tracking.len() <= effect_id {
29 tracking.push(Vec::new());
30 }
31 tracking[effect_id].clear();
32 });
33
34 f();
36
37 CURRENT_EFFECT.with(|c| {
39 c.replace(prev);
40 });
41}
42
43pub fn track_signal(signal_id: usize) {
45 CURRENT_EFFECT.with(|c| {
46 if let Some(effect_id) = *c.borrow() {
47 TRACKING.with(|t| {
48 let mut tracking = t.borrow_mut();
49 if effect_id < tracking.len() {
50 if !tracking[effect_id].contains(&signal_id) {
51 tracking[effect_id].push(signal_id);
52 }
53 }
54 });
55 }
56 });
57}
58
59pub fn get_dependent_effects(signal_id: usize) -> Vec<EffectId> {
61 TRACKING.with(|t| {
62 let tracking = t.borrow();
63 let mut deps = Vec::new();
64 for (effect_id, signals) in tracking.iter().enumerate() {
65 if signals.contains(&signal_id) {
66 deps.push(effect_id);
67 }
68 }
69 deps
70 })
71}
72
73pub fn trigger_effects(signal_id: usize) {
76 let deps = get_dependent_effects(signal_id);
77 EFFECTS.with(|e| {
78 let effects = e.borrow();
79 for dep_id in deps {
80 if dep_id < effects.len() {
81 let effect = &effects[dep_id];
82 track_effect(dep_id, effect);
83 }
84 }
85 });
86}