Skip to main content

islands_runtime/
signal.rs

1use std::cell::RefCell;
2use std::rc::{Rc, Weak};
3use wasm_bindgen::prelude::*;
4
5use crate::effect::{current_subscriber, run_effect, EffectImpl};
6
7struct SignalInner {
8    value: RefCell<JsValue>,
9    subscribers: RefCell<Vec<Weak<EffectImpl>>>,
10}
11
12#[wasm_bindgen]
13pub struct Signal {
14    inner: Rc<SignalInner>,
15}
16
17#[wasm_bindgen]
18impl Signal {
19    #[wasm_bindgen(constructor)]
20    pub fn new(initial: JsValue) -> Signal {
21        Signal {
22            inner: Rc::new(SignalInner {
23                value: RefCell::new(initial),
24                subscribers: RefCell::new(Vec::new()),
25            }),
26        }
27    }
28
29    pub fn get(&self) -> JsValue {
30        if let Some(w) = current_subscriber() {
31            self.inner.subscribers.borrow_mut().push(w);
32        }
33        self.inner.value.borrow().clone()
34    }
35
36    pub fn set(&self, v: JsValue) {
37        *self.inner.value.borrow_mut() = v;
38        let mut subscribers = self.inner.subscribers.borrow_mut();
39        subscribers.retain(|w| w.upgrade().is_some());
40        let live: Vec<Rc<EffectImpl>> = subscribers.iter().filter_map(|w| w.upgrade()).collect();
41        drop(subscribers);
42        for effect_handle in live {
43            run_effect(&effect_handle);
44        }
45    }
46
47    #[wasm_bindgen(js_name = clone_handle)]
48    pub fn clone_handle(&self) -> Signal {
49        Signal {
50            inner: self.inner.clone(),
51        }
52    }
53}