use std::cell::RefCell;
use std::rc::{Rc, Weak};
use wasm_bindgen::prelude::*;
use crate::effect::{current_subscriber, run_effect, EffectImpl};
struct SignalInner {
value: RefCell<JsValue>,
subscribers: RefCell<Vec<Weak<EffectImpl>>>,
}
#[wasm_bindgen]
pub struct Signal {
inner: Rc<SignalInner>,
}
#[wasm_bindgen]
impl Signal {
#[wasm_bindgen(constructor)]
pub fn new(initial: JsValue) -> Signal {
Signal {
inner: Rc::new(SignalInner {
value: RefCell::new(initial),
subscribers: RefCell::new(Vec::new()),
}),
}
}
pub fn get(&self) -> JsValue {
if let Some(w) = current_subscriber() {
self.inner.subscribers.borrow_mut().push(w);
}
self.inner.value.borrow().clone()
}
pub fn set(&self, v: JsValue) {
*self.inner.value.borrow_mut() = v;
let mut subscribers = self.inner.subscribers.borrow_mut();
subscribers.retain(|w| w.upgrade().is_some());
let live: Vec<Rc<EffectImpl>> = subscribers.iter().filter_map(|w| w.upgrade()).collect();
drop(subscribers);
for effect_handle in live {
run_effect(&effect_handle);
}
}
#[wasm_bindgen(js_name = clone_handle)]
pub fn clone_handle(&self) -> Signal {
Signal {
inner: self.inner.clone(),
}
}
}