rate_ui/
shared_object.rs

1use crate::storage::typed_storage::{Storable, TypedStorage};
2use crate::widget::{Context, NotificationHandler};
3use std::cell::{Ref, RefCell, RefMut};
4use std::marker::PhantomData;
5use std::ops::{Deref, DerefMut};
6use std::rc::Rc;
7use typed_slab::TypedSlab;
8use yew::Callback;
9
10pub trait RouterState: PartialEq + Storable + Default + Clone + 'static {
11    /// Called when the state restored.
12    ///
13    /// For the case when some data should be reset of expired.
14    fn restored(&mut self);
15
16    // TODO: Remove it completely!
17    fn update(&mut self, new_state: Self) {
18        *self = new_state;
19    }
20
21    fn on_update(&mut self) {}
22}
23
24pub struct DataChanged<T> {
25    _data: PhantomData<T>,
26}
27
28impl<T> DataChanged<T> {
29    fn new() -> Self {
30        Self { _data: PhantomData }
31    }
32}
33
34#[derive(Debug)]
35pub struct SharedObject<T> {
36    inner: Rc<RefCell<SharedObjectInner<T>>>,
37    listener: Option<ListenerId>,
38}
39
40impl<T> Clone for SharedObject<T> {
41    fn clone(&self) -> Self {
42        Self {
43            inner: self.inner.clone(),
44            listener: None,
45        }
46    }
47}
48
49impl<T> Drop for SharedObject<T> {
50    fn drop(&mut self) {
51        self.unsubscribe();
52    }
53}
54
55impl<T> Default for SharedObject<T>
56where
57    T: RouterState + Default,
58{
59    fn default() -> Self {
60        Self::new()
61    }
62}
63
64impl<T> SharedObject<T> {
65    pub fn new() -> Self
66    where
67        T: RouterState + Default,
68    {
69        let storage = TypedStorage::new();
70        let mut data: T = storage.restore().unwrap_or_default();
71        data.restored();
72        let inner = SharedObjectInner {
73            callbacks: TypedSlab::new(),
74            data,
75        };
76        Self {
77            inner: Rc::new(RefCell::new(inner)),
78            listener: None,
79        }
80    }
81
82    pub fn subscribe<W>(&mut self, context: &mut Context<W>)
83    where
84        W: NotificationHandler<DataChanged<T>>,
85        T: 'static,
86    {
87        self.unsubscribe();
88        let callback = context.notification();
89        let mut writer = self.inner.borrow_mut();
90        let id = writer.callbacks.insert(callback);
91        self.listener = Some(id);
92    }
93
94    pub fn unsubscribe(&mut self) {
95        if let Some(id) = self.listener.take() {
96            let mut writer = self.inner.borrow_mut();
97            writer.callbacks.remove(id);
98        }
99    }
100
101    pub fn read(&self) -> SharedObjectReader<'_, T> {
102        let reader = self.inner.borrow();
103        SharedObjectReader { reader }
104    }
105
106    pub fn write(&self) -> SharedObjectWriter<'_, T>
107    where
108        T: RouterState,
109    {
110        let writer = self.inner.borrow_mut();
111        SharedObjectWriter { writer }
112    }
113}
114
115pub struct SharedObjectReader<'a, T> {
116    reader: Ref<'a, SharedObjectInner<T>>,
117}
118
119impl<'a, T> Deref for SharedObjectReader<'a, T> {
120    type Target = T;
121
122    fn deref(&self) -> &Self::Target {
123        &self.reader.data
124    }
125}
126
127pub struct SharedObjectWriter<'a, T: RouterState> {
128    writer: RefMut<'a, SharedObjectInner<T>>,
129}
130
131impl<'a, T> Deref for SharedObjectWriter<'a, T>
132where
133    T: RouterState,
134{
135    type Target = T;
136
137    fn deref(&self) -> &Self::Target {
138        &self.writer.data
139    }
140}
141
142impl<'a, T> DerefMut for SharedObjectWriter<'a, T>
143where
144    T: RouterState,
145{
146    fn deref_mut(&mut self) -> &mut Self::Target {
147        &mut self.writer.data
148    }
149}
150
151impl<'a, T> Drop for SharedObjectWriter<'a, T>
152where
153    T: RouterState,
154{
155    fn drop(&mut self) {
156        self.writer.data.on_update();
157        // TODO: Avoid creating it every time. Or is it cheap?
158        let mut storage = TypedStorage::new();
159        storage.store(&self.writer.data);
160        for (_, callback) in self.writer.callbacks.iter() {
161            callback.emit(DataChanged::new());
162        }
163    }
164}
165
166type ListenerId = usize;
167
168#[derive(Debug)]
169struct SharedObjectInner<T> {
170    callbacks: TypedSlab<ListenerId, Callback<DataChanged<T>>>,
171    data: T,
172}