islands_runtime/
signal.rs1use 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}