maple_core/reactive/
signal.rs1use super::*;
2use std::cell::RefCell;
3use std::collections::HashSet;
4use std::fmt;
5use std::ops::Deref;
6use std::rc::Rc;
7
8pub struct StateHandle<T: 'static>(Rc<RefCell<SignalInner<T>>>);
13
14impl<T: 'static> StateHandle<T> {
15 pub fn get(&self) -> Rc<T> {
17 CONTEXTS.with(|contexts| {
19 if let Some(last_context) = contexts.borrow().last() {
20 let signal = Rc::downgrade(&self.0);
21
22 last_context
23 .upgrade()
24 .expect("Running should be valid while inside reactive scope")
25 .borrow_mut()
26 .as_mut()
27 .unwrap()
28 .dependencies
29 .insert(Dependency(signal));
30 }
31 });
32
33 self.get_untracked()
34 }
35
36 pub fn get_untracked(&self) -> Rc<T> {
58 Rc::clone(&self.0.borrow().inner)
59 }
60}
61
62impl<T: 'static> Clone for StateHandle<T> {
63 fn clone(&self) -> Self {
64 Self(Rc::clone(&self.0))
65 }
66}
67
68impl<T: fmt::Debug> fmt::Debug for StateHandle<T> {
69 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
70 f.debug_tuple("StateHandle")
71 .field(&self.get_untracked())
72 .finish()
73 }
74}
75
76#[cfg(feature = "serde")]
77impl<T: serde::Serialize> serde::Serialize for StateHandle<T> {
78 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
79 where
80 S: serde::Serializer,
81 {
82 self.get_untracked().as_ref().serialize(serializer)
83 }
84}
85
86#[cfg(feature = "serde")]
87impl<'de, T: serde::Deserialize<'de>> serde::Deserialize<'de> for StateHandle<T> {
88 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
89 where
90 D: serde::Deserializer<'de>,
91 {
92 Ok(Signal::new(T::deserialize(deserializer)?).handle())
93 }
94}
95
96pub struct Signal<T: 'static> {
109 handle: StateHandle<T>,
110}
111
112impl<T: 'static> Signal<T> {
113 pub fn new(value: T) -> Self {
122 Self {
123 handle: StateHandle(Rc::new(RefCell::new(SignalInner::new(value)))),
124 }
125 }
126
127 pub fn set(&self, new_value: T) {
142 self.handle.0.borrow_mut().update(new_value);
143
144 self.trigger_subscribers();
145 }
146
147 pub fn handle(&self) -> StateHandle<T> {
151 self.handle.clone()
152 }
153
154 pub fn into_handle(self) -> StateHandle<T> {
156 self.handle
157 }
158
159 pub fn trigger_subscribers(&self) {
163 let subscribers = self.handle.0.borrow().subscribers.clone();
165
166 for subscriber in subscribers {
167 if let Some(callback) = subscriber.try_callback() {
169 callback()
170 }
171 }
172 }
173}
174
175impl<T: 'static> Deref for Signal<T> {
176 type Target = StateHandle<T>;
177
178 fn deref(&self) -> &Self::Target {
179 &self.handle
180 }
181}
182
183impl<T: 'static> Clone for Signal<T> {
184 fn clone(&self) -> Self {
185 Self {
186 handle: self.handle.clone(),
187 }
188 }
189}
190
191impl<T: PartialEq> PartialEq for Signal<T> {
192 fn eq(&self, other: &Signal<T>) -> bool {
193 self.get_untracked().eq(&other.get_untracked())
194 }
195}
196
197impl<T: fmt::Debug> fmt::Debug for Signal<T> {
198 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
199 f.debug_tuple("Signal")
200 .field(&self.get_untracked())
201 .finish()
202 }
203}
204
205#[cfg(feature = "serde")]
206impl<T: serde::Serialize> serde::Serialize for Signal<T> {
207 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
208 where
209 S: serde::Serializer,
210 {
211 self.get_untracked().as_ref().serialize(serializer)
212 }
213}
214
215#[cfg(feature = "serde")]
216impl<'de, T: serde::Deserialize<'de>> serde::Deserialize<'de> for Signal<T> {
217 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
218 where
219 D: serde::Deserializer<'de>,
220 {
221 Ok(Signal::new(T::deserialize(deserializer)?))
222 }
223}
224
225pub(super) struct SignalInner<T> {
226 inner: Rc<T>,
227 subscribers: HashSet<Callback>,
228}
229
230impl<T> SignalInner<T> {
231 fn new(value: T) -> Self {
232 Self {
233 inner: Rc::new(value),
234 subscribers: HashSet::new(),
235 }
236 }
237
238 fn subscribe(&mut self, handler: Callback) {
240 self.subscribers.insert(handler);
241 }
242
243 fn unsubscribe(&mut self, handler: &Callback) {
245 self.subscribers.remove(handler);
246 }
247
248 fn update(&mut self, new_value: T) {
251 self.inner = Rc::new(new_value);
252 }
253}
254
255pub(super) trait AnySignalInner {
257 fn subscribe(&self, handler: Callback);
259 fn unsubscribe(&self, handler: &Callback);
261}
262
263impl<T> AnySignalInner for RefCell<SignalInner<T>> {
264 fn subscribe(&self, handler: Callback) {
265 self.borrow_mut().subscribe(handler);
266 }
267
268 fn unsubscribe(&self, handler: &Callback) {
269 self.borrow_mut().unsubscribe(handler);
270 }
271}
272
273#[cfg(test)]
274mod tests {
275 use super::*;
276
277 #[test]
278 fn signals() {
279 let state = Signal::new(0);
280 assert_eq!(*state.get(), 0);
281
282 state.set(1);
283 assert_eq!(*state.get(), 1);
284 }
285
286 #[test]
287 fn signal_composition() {
288 let state = Signal::new(0);
289
290 let double = || *state.get() * 2;
291
292 assert_eq!(double(), 0);
293
294 state.set(1);
295 assert_eq!(double(), 2);
296 }
297
298 #[test]
299 fn state_handle() {
300 let state = Signal::new(0);
301 let readonly = state.handle();
302
303 assert_eq!(*readonly.get(), 0);
304
305 state.set(1);
306 assert_eq!(*readonly.get(), 1);
307 }
308}