floem_reactive/
signal.rs

1use std::{
2    any::Any,
3    cell::{Ref, RefCell},
4    collections::HashMap,
5    fmt,
6    marker::PhantomData,
7    rc::Rc,
8};
9
10use crate::{
11    effect::{run_effect, EffectTrait},
12    id::Id,
13    read::{SignalRead, SignalTrack, SignalWith},
14    runtime::RUNTIME,
15    write::SignalWrite,
16    SignalGet, SignalUpdate,
17};
18
19/// Marker type explaining why something can't be sent across threads
20/// If you need to synchronize data into a signal from another thread, use `create_signal_from_channel` or a similar constructor.
21#[allow(dead_code)]
22pub struct NotThreadSafe(*const ());
23
24/// A read write Signal which can act as both a Getter and a Setter
25pub struct RwSignal<T> {
26    pub(crate) id: Id,
27    pub(crate) ty: PhantomData<T>,
28    pub(crate) ts: PhantomData<NotThreadSafe>,
29}
30
31impl<T> Copy for RwSignal<T> {}
32
33impl<T> Clone for RwSignal<T> {
34    fn clone(&self) -> Self {
35        *self
36    }
37}
38
39impl<T> Eq for RwSignal<T> {}
40
41impl<T> PartialEq for RwSignal<T> {
42    fn eq(&self, other: &Self) -> bool {
43        self.id == other.id
44    }
45}
46
47impl<T> fmt::Debug for RwSignal<T> {
48    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
49        let mut s = f.debug_struct("RwSignal");
50        s.field("id", &self.id);
51        s.field("ty", &self.ty);
52        s.finish()
53    }
54}
55
56impl<T: Default + 'static> Default for RwSignal<T> {
57    fn default() -> Self {
58        RwSignal::new(T::default())
59    }
60}
61
62impl<T> RwSignal<T> {
63    /// Create a Getter of this Signal
64    pub fn read_only(&self) -> ReadSignal<T> {
65        ReadSignal {
66            id: self.id,
67            ty: PhantomData,
68            ts: PhantomData,
69        }
70    }
71
72    /// Create a Setter of this Signal
73    pub fn write_only(&self) -> WriteSignal<T> {
74        WriteSignal {
75            id: self.id,
76            ty: PhantomData,
77            ts: PhantomData,
78        }
79    }
80}
81
82impl<T: 'static> RwSignal<T> {
83    pub fn new(value: T) -> Self {
84        create_rw_signal(value)
85    }
86    pub fn new_split(value: T) -> (ReadSignal<T>, WriteSignal<T>) {
87        let sig = Self::new(value);
88        (sig.read_only(), sig.write_only())
89    }
90}
91
92/// Creates a new RwSignal which can act both as a setter and a getter.
93///
94/// Accessing the signal value in an Effect will make the Effect subscribe
95/// to the value change of the Signal. And whenever the signal value changes,
96/// it will trigger an effect run.
97pub fn create_rw_signal<T>(value: T) -> RwSignal<T>
98where
99    T: Any + 'static,
100{
101    let id = Signal::create(value);
102    id.set_scope();
103    RwSignal {
104        id,
105        ty: PhantomData,
106        ts: PhantomData,
107    }
108}
109
110/// A getter only Signal
111pub struct ReadSignal<T> {
112    pub(crate) id: Id,
113    pub(crate) ty: PhantomData<T>,
114    pub(crate) ts: PhantomData<NotThreadSafe>,
115}
116
117impl<T> Copy for ReadSignal<T> {}
118
119impl<T> Clone for ReadSignal<T> {
120    fn clone(&self) -> Self {
121        *self
122    }
123}
124
125impl<T> Eq for ReadSignal<T> {}
126
127impl<T> PartialEq for ReadSignal<T> {
128    fn eq(&self, other: &Self) -> bool {
129        self.id == other.id
130    }
131}
132
133/// A setter only Signal
134pub struct WriteSignal<T> {
135    pub(crate) id: Id,
136    pub(crate) ty: PhantomData<T>,
137    pub(crate) ts: PhantomData<NotThreadSafe>,
138}
139
140impl<T> Copy for WriteSignal<T> {}
141
142impl<T> Clone for WriteSignal<T> {
143    fn clone(&self) -> Self {
144        *self
145    }
146}
147
148impl<T> Eq for WriteSignal<T> {}
149
150impl<T> PartialEq for WriteSignal<T> {
151    fn eq(&self, other: &Self) -> bool {
152        self.id == other.id
153    }
154}
155
156/// Creates a new setter and getter Signal.
157///
158/// Accessing the signal value in an Effect will make the Effect subscribe
159/// to the value change of the Signal. And whenever the signal value changes,
160/// it will trigger an effect run.
161pub fn create_signal<T>(value: T) -> (ReadSignal<T>, WriteSignal<T>)
162where
163    T: Any + 'static,
164{
165    let s = create_rw_signal(value);
166    (s.read_only(), s.write_only())
167}
168
169/// The internal Signal where the value is stored, and effects are stored.
170#[derive(Clone)]
171pub(crate) struct Signal {
172    pub(crate) id: Id,
173    pub(crate) value: Rc<dyn Any>,
174    pub(crate) subscribers: Rc<RefCell<HashMap<Id, Rc<dyn EffectTrait>>>>,
175    pub(crate) ts: PhantomData<NotThreadSafe>,
176}
177
178impl Signal {
179    pub fn create<T>(value: T) -> Id
180    where
181        T: Any + 'static,
182    {
183        let id = Id::next();
184        let value = RefCell::new(value);
185        let signal = Signal {
186            id,
187            subscribers: Rc::new(RefCell::new(HashMap::new())),
188            value: Rc::new(value),
189            ts: PhantomData,
190        };
191        id.add_signal(signal);
192        id
193    }
194
195    pub fn borrow<T: 'static>(&self) -> Ref<'_, T> {
196        let value = self
197            .value
198            .downcast_ref::<RefCell<T>>()
199            .expect("to downcast signal type");
200        value.borrow()
201    }
202
203    pub(crate) fn get_untracked<T: Clone + 'static>(&self) -> T {
204        let value = self.borrow::<T>();
205        value.clone()
206    }
207
208    pub(crate) fn get<T: Clone + 'static>(&self) -> T {
209        self.subscribe();
210        self.get_untracked()
211    }
212
213    pub(crate) fn with_untracked<O, T: 'static>(&self, f: impl FnOnce(&T) -> O) -> O {
214        let value = self.borrow::<T>();
215        f(&value)
216    }
217
218    pub(crate) fn with<O, T: 'static>(&self, f: impl FnOnce(&T) -> O) -> O {
219        self.subscribe();
220        self.with_untracked(f)
221    }
222
223    pub(crate) fn update_value<U, T: 'static>(&self, f: impl FnOnce(&mut T) -> U) -> U {
224        let result = self
225            .value
226            .downcast_ref::<RefCell<T>>()
227            .expect("to downcast signal type");
228        let result = f(&mut result.borrow_mut());
229        self.run_effects();
230        result
231    }
232
233    pub(crate) fn subscribers(&self) -> HashMap<Id, Rc<dyn EffectTrait>> {
234        self.subscribers.borrow().clone()
235    }
236
237    pub(crate) fn run_effects(&self) {
238        // If we are batching then add it as a pending effect
239        if RUNTIME.with(|r| r.batching.get()) {
240            RUNTIME.with(|r| {
241                for (_, subscriber) in self.subscribers() {
242                    r.add_pending_effect(subscriber);
243                }
244            });
245            return;
246        }
247
248        for (_, subscriber) in self.subscribers() {
249            run_effect(subscriber);
250        }
251    }
252
253    pub(crate) fn subscribe(&self) {
254        RUNTIME.with(|runtime| {
255            if let Some(effect) = runtime.current_effect.borrow().as_ref() {
256                self.subscribers
257                    .borrow_mut()
258                    .insert(effect.id(), effect.clone());
259                effect.add_observer(self.id);
260            }
261        });
262    }
263}
264
265impl<T: Clone> SignalGet<T> for RwSignal<T> {
266    fn id(&self) -> Id {
267        self.id
268    }
269}
270
271impl<T> SignalWith<T> for RwSignal<T> {
272    fn id(&self) -> Id {
273        self.id
274    }
275}
276
277impl<T> SignalTrack<T> for RwSignal<T> {
278    fn id(&self) -> Id {
279        self.id
280    }
281}
282
283impl<T> SignalRead<T> for RwSignal<T> {
284    fn id(&self) -> Id {
285        self.id
286    }
287}
288
289impl<T> SignalUpdate<T> for RwSignal<T> {
290    fn id(&self) -> Id {
291        self.id
292    }
293}
294
295impl<T> SignalWrite<T> for RwSignal<T> {
296    fn id(&self) -> Id {
297        self.id
298    }
299}
300
301impl<T: Clone> SignalGet<T> for ReadSignal<T> {
302    fn id(&self) -> Id {
303        self.id
304    }
305}
306
307impl<T> SignalWith<T> for ReadSignal<T> {
308    fn id(&self) -> Id {
309        self.id
310    }
311}
312
313impl<T> SignalTrack<T> for ReadSignal<T> {
314    fn id(&self) -> Id {
315        self.id
316    }
317}
318
319impl<T> SignalRead<T> for ReadSignal<T> {
320    fn id(&self) -> Id {
321        self.id
322    }
323}
324
325impl<T> SignalUpdate<T> for WriteSignal<T> {
326    fn id(&self) -> Id {
327        self.id
328    }
329}
330
331impl<T> SignalWrite<T> for WriteSignal<T> {
332    fn id(&self) -> Id {
333        self.id
334    }
335}