floem_reactive/
write.rs

1use std::{
2    cell::{RefCell, RefMut},
3    marker::PhantomData,
4    rc::Rc,
5};
6
7use crate::{id::Id, signal::NotThreadSafe};
8
9#[derive(Clone)]
10pub struct WriteSignalValue<T> {
11    pub(crate) id: Id,
12    pub(crate) value: Rc<RefCell<T>>,
13    pub(crate) ts: PhantomData<NotThreadSafe>,
14}
15
16impl<T> Drop for WriteSignalValue<T> {
17    fn drop(&mut self) {
18        if let Some(signal) = self.id.signal() {
19            signal.run_effects();
20        }
21    }
22}
23
24impl<T> WriteSignalValue<T> {
25    /// Mutably borrows the current value stored in the Signal
26    pub fn borrow_mut(&self) -> RefMut<'_, T> {
27        self.value.borrow_mut()
28    }
29}
30
31pub trait SignalUpdate<T> {
32    /// get the Signal Id
33    fn id(&self) -> Id;
34
35    /// Sets the new_value to the Signal and triggers effect run
36    fn set(&self, new_value: T)
37    where
38        T: 'static,
39    {
40        if let Some(signal) = self.id().signal() {
41            signal.update_value(|v| *v = new_value);
42        }
43    }
44
45    /// Update the stored value with the given function and triggers effect run
46    fn update(&self, f: impl FnOnce(&mut T))
47    where
48        T: 'static,
49    {
50        if let Some(signal) = self.id().signal() {
51            signal.update_value(f);
52        }
53    }
54
55    /// Update the stored value with the given function, triggers effect run,
56    /// and returns the value returned by the function
57    fn try_update<O>(&self, f: impl FnOnce(&mut T) -> O) -> Option<O>
58    where
59        T: 'static,
60    {
61        self.id().signal().map(|signal| signal.update_value(f))
62    }
63}
64
65pub trait SignalWrite<T> {
66    /// get the Signal Id
67    fn id(&self) -> Id;
68    /// Convert the Signal to `WriteSignalValue` where it holds a RefCell wrapped
69    /// original data of the signal, so that you can `borrow_mut()` to update the data.
70    ///
71    /// When `WriteSignalValue` drops, it triggers effect run
72    fn write(&self) -> WriteSignalValue<T>
73    where
74        T: 'static,
75    {
76        self.try_write().unwrap()
77    }
78
79    /// If the Signal isn't disposed,
80    /// convert the Signal to `WriteSignalValue` where it holds a RefCell wrapped
81    /// original data of the signal, so that you can `borrow_mut()` to update the data.
82    ///
83    /// When `WriteSignalValue` drops, it triggers effect run
84    fn try_write(&self) -> Option<WriteSignalValue<T>>
85    where
86        T: 'static,
87    {
88        if let Some(signal) = self.id().signal() {
89            Some(WriteSignalValue {
90                id: signal.id,
91                value: signal
92                    .value
93                    .clone()
94                    .downcast::<RefCell<T>>()
95                    .expect("to downcast signal type"),
96                ts: PhantomData,
97            })
98        } else {
99            None
100        }
101    }
102}