observable_react/
traits.rs

1use std::cell::Ref;
2
3use dyn_clone::DynClone;
4use js_sys::Function;
5use observable_rs::{ListenerHandle, Observable};
6// use serde::{de::DeserializeOwned, Serialize};
7use wasm_bindgen::JsValue;
8
9use crate::collections::List;
10
11// Traits for javascript-specific functionality around Observable<T>
12
13/// This trait is necessary to support generic observables
14/// which cannot themselves be exportable via wasm_bindgen
15pub trait JsObserve: DynClone {
16    // type Target: Clone + Into<JsValue>;
17
18    fn get_js(&self) -> JsValue;
19
20    /// The default implementation of map is to call the closure once
21    /// with the output of .get - other types may call the closure multiple
22    /// times for different sub-values
23    fn map_js(&self, cb: Function) -> JsValue {
24        let ar = js_sys::Array::new();
25        let ret = cb.call1(&JsValue::UNDEFINED, &self.get_js()).unwrap();
26        ar.push(&ret);
27        ar.into()
28    }
29
30    fn unsubscribe(&self, handle: ListenerHandle) -> bool;
31
32    fn subscribe(&self, cb: Box<dyn Fn(JsValue)>) -> ListenerHandle;
33    fn once(&self, cb: Box<dyn Fn(JsValue)>) -> ListenerHandle;
34}
35
36impl<T> JsObserve for Observable<T>
37where
38    T: Into<JsValue> + Clone,
39{
40    // we need to be able provide a JS value (JS only has one value type)
41    fn get_js(&self) -> JsValue {
42        let a: Ref<T> = self.get();
43        (*a).clone().into()
44    }
45
46    fn subscribe(&self, cb: Box<dyn Fn(JsValue)>) -> ListenerHandle {
47        Observable::subscribe(self, Box::new(move |v: &T| cb(v.clone().into())))
48    }
49
50    fn once(&self, cb: Box<dyn Fn(JsValue)>) -> ListenerHandle {
51        Observable::once(self, Box::new(move |v: &T| cb(v.clone().into())))
52    }
53
54    fn unsubscribe(&self, handle: ListenerHandle) -> bool {
55        Observable::unsubscribe(self, handle)
56    }
57}
58
59impl<T> JsObserve for Observable<List<T>>
60where
61    T: Into<JsValue> + Clone,
62{
63    // we need to be able provide a JS value (JS only has one value type)
64    fn get_js(&self) -> JsValue {
65        let a: Ref<List<T>> = self.get();
66        (&*a).into()
67    }
68
69    fn subscribe(&self, cb: Box<dyn Fn(JsValue)>) -> ListenerHandle {
70        Observable::subscribe(self, Box::new(move |v: &List<T>| cb(v.into())))
71    }
72
73    fn once(&self, cb: Box<dyn Fn(JsValue)>) -> ListenerHandle {
74        Observable::once(self, Box::new(move |v: &List<T>| cb(v.into())))
75    }
76
77    fn unsubscribe(&self, handle: ListenerHandle) -> bool {
78        Observable::unsubscribe(self, handle)
79    }
80}