1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
use dyn_clone::DynClone;
use js_sys::Function;
use observable_rs::{ListenerHandle, Observable};
use serde::{de::DeserializeOwned, Serialize};
use wasm_bindgen::JsValue;

// Traits for javascript-specific functionality around Observable<T>

/// This trait is necessary to support generic observables
/// which cannot themselves be exportable via wasm_bindgen
pub trait JsObserveBase {
    fn get_js(&self) -> JsValue;
    fn subscribe(&self, cb: Box<dyn Fn()>) -> ListenerHandle;
    fn once(&self, cb: Box<dyn Fn()>) -> ListenerHandle;
    fn unsubscribe(&self, handle: ListenerHandle) -> bool;
    // fn destroy(&self);
}
pub trait JsObserve: JsObserveBase + JsObserveMap + DynClone {}

pub trait JsObserveMap {
    fn map_js(&self, cb: Function) -> JsValue;
}

// TODO - Figure out why rust thinks this is unbound when we impl JsObserveBase for O where O: Observe<T>
impl<T> JsObserveBase for Observable<T>
where
    // O: Observe<T> + Clone,
    T: Serialize + DeserializeOwned,
{
    // we need to be able provide a JS value (JS only has one value type)
    fn get_js(&self) -> JsValue {
        JsValue::from_serde(&*self.get()).unwrap()
    }

    fn subscribe(&self, cb: Box<dyn Fn()>) -> ListenerHandle {
        Self::subscribe(self, cb)
    }

    fn once(&self, cb: Box<dyn Fn()>) -> ListenerHandle {
        Self::once(self, cb)
    }

    fn unsubscribe(&self, handle: ListenerHandle) -> bool {
        Self::unsubscribe(self, handle)
    }

    // fn destroy(&self) {
    //     todo!("destroy method needs doing in ReactObservable");
    // }
}