floem_reactive/
write.rs

1use std::{
2    ops::{Deref, DerefMut},
3    rc::Rc,
4    sync::Arc,
5};
6
7use parking_lot::{Mutex, MutexGuard};
8
9use crate::{id::Id, signal::TrackedRefCell};
10
11pub struct SyncWriteRef<'a, T> {
12    id: Id,
13    _handle: Arc<Mutex<T>>,
14    pub(crate) guard: Option<MutexGuard<'a, T>>,
15}
16
17pub struct LocalWriteRef<'a, T> {
18    id: Id,
19    _handle: Rc<TrackedRefCell<T>>,
20    pub(crate) guard: Option<crate::signal::TrackedRefMut<'a, T>>,
21}
22
23pub enum WriteRef<'a, T> {
24    Sync(SyncWriteRef<'a, T>),
25    Local(LocalWriteRef<'a, T>),
26}
27
28impl<'a, T> SyncWriteRef<'a, T> {
29    pub(crate) fn new(id: Id, handle: Arc<Mutex<T>>) -> Self {
30        let guard = handle.lock();
31        let guard = unsafe { std::mem::transmute::<MutexGuard<'_, T>, MutexGuard<'a, T>>(guard) };
32        Self {
33            id,
34            _handle: handle,
35            guard: Some(guard),
36        }
37    }
38}
39
40impl<'a, T> Drop for SyncWriteRef<'a, T> {
41    fn drop(&mut self) {
42        if let Some(guard) = self.guard.take() {
43            drop(guard);
44        }
45        if let Some(signal) = self.id.signal() {
46            signal.run_effects();
47        }
48    }
49}
50
51impl<'a, T> LocalWriteRef<'a, T> {
52    pub(crate) fn new(id: Id, handle: Rc<TrackedRefCell<T>>) -> Self {
53        let guard = handle.borrow_mut();
54        let guard = unsafe {
55            std::mem::transmute::<
56                crate::signal::TrackedRefMut<'_, T>,
57                crate::signal::TrackedRefMut<'a, T>,
58            >(guard)
59        };
60        Self {
61            id,
62            _handle: handle,
63            guard: Some(guard),
64        }
65    }
66}
67
68impl<'a, T> Drop for LocalWriteRef<'a, T> {
69    fn drop(&mut self) {
70        if let Some(guard) = self.guard.take() {
71            drop(guard);
72        }
73        if let Some(signal) = self.id.signal() {
74            signal.run_effects();
75        }
76    }
77}
78
79impl<'a, T> Deref for WriteRef<'a, T> {
80    type Target = T;
81    fn deref(&self) -> &Self::Target {
82        match self {
83            WriteRef::Sync(v) => v.guard.as_ref().expect("guard present"),
84            WriteRef::Local(v) => v.guard.as_ref().expect("guard present"),
85        }
86    }
87}
88
89impl<'a, T> DerefMut for WriteRef<'a, T> {
90    fn deref_mut(&mut self) -> &mut Self::Target {
91        match self {
92            WriteRef::Sync(v) => &mut *v.guard.as_mut().expect("guard present"),
93            WriteRef::Local(v) => &mut *v.guard.as_mut().expect("guard present"),
94        }
95    }
96}
97
98pub trait SignalUpdate<T> {
99    /// get the Signal Id
100    fn id(&self) -> Id;
101
102    /// Sets the new_value to the Signal and triggers effect run
103    fn set(&self, new_value: T)
104    where
105        T: 'static,
106    {
107        let _ = self.try_update(|v| *v = new_value);
108    }
109
110    /// Update the stored value with the given function and triggers effect run
111    fn update(&self, f: impl FnOnce(&mut T))
112    where
113        T: 'static,
114    {
115        let _ = self.try_update(f);
116    }
117
118    /// Update the stored value with the given function, triggers effect run,
119    /// and returns the value returned by the function
120    fn try_update<O>(&self, f: impl FnOnce(&mut T) -> O) -> Option<O>
121    where
122        T: 'static;
123}
124
125pub trait SignalWrite<T> {
126    /// get the Signal Id
127    fn id(&self) -> Id;
128    /// Mutably borrows the signal value, triggering subscribers when dropped.
129    fn write(&self) -> WriteRef<'_, T>
130    where
131        T: 'static,
132    {
133        self.try_write().unwrap()
134    }
135
136    /// If the Signal isn't disposed, mutably borrows the signal value.
137    fn try_write(&self) -> Option<WriteRef<'_, T>>
138    where
139        T: 'static;
140}