floem_reactive/
derived.rs

1use std::marker::PhantomData;
2
3use crate::{
4    storage::{SyncStorage, UnsyncStorage},
5    RwSignal, SignalGet, SignalTrack, SignalUpdate, SignalWith,
6};
7
8/// A derived signal backed by a local [`RwSignal`] (UI-thread only).
9pub struct DerivedRwSignal<
10    T: 'static,
11    O,
12    GF: Fn(&T) -> O + Clone + 'static,
13    UF: Fn(&O) -> T + Clone + 'static,
14> {
15    signal: RwSignal<T, UnsyncStorage>,
16    getter: RwSignal<Box<GF>, UnsyncStorage>,
17    setter: RwSignal<Box<UF>, UnsyncStorage>,
18    ty: PhantomData<T>,
19    ts: PhantomData<()>,
20}
21
22impl<T, O, GF, UF> Clone for DerivedRwSignal<T, O, GF, UF>
23where
24    GF: Fn(&T) -> O + Copy,
25    UF: Fn(&O) -> T + Copy,
26{
27    fn clone(&self) -> Self {
28        *self
29    }
30}
31
32impl<T, O, GF, UF> Copy for DerivedRwSignal<T, O, GF, UF>
33where
34    GF: Fn(&T) -> O + Copy,
35    UF: Fn(&O) -> T + Copy,
36{
37}
38
39impl<T, O, GF, UF> SignalGet<O> for DerivedRwSignal<T, O, GF, UF>
40where
41    T: Clone + 'static,
42    O: Clone + 'static,
43    GF: Fn(&T) -> O + Copy + 'static,
44    UF: Fn(&O) -> T + Copy + 'static,
45{
46    fn id(&self) -> crate::id::Id {
47        self.signal.id
48    }
49
50    fn get_untracked(&self) -> O
51    where
52        O: 'static,
53    {
54        self.try_get_untracked().unwrap()
55    }
56
57    fn get(&self) -> O
58    where
59        O: 'static,
60    {
61        self.try_get().unwrap()
62    }
63
64    fn try_get(&self) -> Option<O>
65    where
66        O: 'static,
67    {
68        let sig = self.getter;
69        self.signal.id.signal().map(|signal| {
70            let func = sig.get_untracked();
71            func(&signal.get()).clone()
72        })
73    }
74
75    fn try_get_untracked(&self) -> Option<O>
76    where
77        O: 'static,
78    {
79        let sig = self.getter;
80        self.signal.id.signal().map(|signal| {
81            let func = sig.get_untracked();
82            func(&signal.get_untracked()).clone()
83        })
84    }
85}
86
87impl<T, O, GF, UF> SignalWith<O> for DerivedRwSignal<T, O, GF, UF>
88where
89    T: Clone + 'static,
90    O: Clone,
91    GF: Fn(&T) -> O + Copy,
92    UF: Fn(&O) -> T + Copy,
93{
94    fn id(&self) -> crate::id::Id {
95        self.signal.id
96    }
97
98    fn with<O2>(&self, f: impl FnOnce(&O) -> O2) -> O2
99    where
100        T: 'static,
101    {
102        let func = self.getter.get_untracked();
103        self.signal.id.signal().unwrap().with(|t| f(&func(t)))
104    }
105
106    fn with_untracked<O2>(&self, f: impl FnOnce(&O) -> O2) -> O2
107    where
108        T: 'static,
109    {
110        let func = self.getter.get_untracked();
111        self.signal
112            .id
113            .signal()
114            .unwrap()
115            .with_untracked(|t| f(&func(t)))
116    }
117
118    fn try_with<O2>(&self, f: impl FnOnce(Option<&O>) -> O2) -> O2
119    where
120        T: 'static,
121    {
122        if let Some(signal) = self.signal.id.signal() {
123            let func = self.getter.get_untracked();
124            signal.with(|v| f(Some(&func(v))))
125        } else {
126            f(None)
127        }
128    }
129
130    fn try_with_untracked<O2>(&self, f: impl FnOnce(Option<&O>) -> O2) -> O2
131    where
132        T: 'static,
133    {
134        if let Some(signal) = self.signal.id.signal() {
135            let func = self.getter.get_untracked();
136            signal.with_untracked(|v| f(Some(&func(v))))
137        } else {
138            f(None)
139        }
140    }
141}
142
143impl<T, O, GF, UF> SignalTrack<O> for DerivedRwSignal<T, O, GF, UF>
144where
145    T: Clone + 'static,
146    O: Clone,
147    GF: Fn(&T) -> O + Copy,
148    UF: Fn(&O) -> T + Copy,
149{
150    fn id(&self) -> crate::id::Id {
151        self.signal.id
152    }
153}
154
155impl<T, O, GF, UF> SignalUpdate<O> for DerivedRwSignal<T, O, GF, UF>
156where
157    T: 'static,
158    O: 'static,
159    GF: Fn(&T) -> O + Copy + 'static,
160    UF: Fn(&O) -> T + Copy + 'static,
161{
162    fn id(&self) -> crate::id::Id {
163        self.signal.id
164    }
165
166    fn set(&self, new_value: O)
167    where
168        O: 'static,
169    {
170        if let Some(signal) = self.id().signal() {
171            let func = self.setter.get_untracked();
172            signal.update_value_local::<_, T>(|v| {
173                let new = func(&new_value);
174                *v = new;
175            });
176        }
177    }
178
179    fn update(&self, f: impl FnOnce(&mut O))
180    where
181        O: 'static,
182    {
183        if let Some(signal) = self.id().signal() {
184            let get_func = self.getter.get_untracked();
185            let set_func = self.setter.get_untracked();
186            signal.update_value_local::<_, T>(|cv| {
187                let mut new = get_func(cv);
188                f(&mut new);
189                let new = set_func(&new);
190                *cv = new;
191            });
192        }
193    }
194
195    fn try_update<O2>(&self, f: impl FnOnce(&mut O) -> O2) -> Option<O2>
196    where
197        O: 'static,
198    {
199        self.id().signal().map(|signal| {
200            let get_func = self.getter.get_untracked();
201            let set_func = self.setter.get_untracked();
202            signal.update_value_local::<_, T>(|cv| {
203                let mut new = get_func(cv);
204                let ret = f(&mut new);
205                let new = set_func(&new);
206                *cv = new;
207                ret
208            })
209        })
210    }
211}
212
213impl<T, O, GF, UF> DerivedRwSignal<T, O, GF, UF>
214where
215    T: 'static,
216    O: 'static,
217    GF: Fn(&T) -> O + Clone + 'static,
218    UF: Fn(&O) -> T + Clone + 'static,
219{
220    pub fn new(signal: RwSignal<T, UnsyncStorage>, getter: GF, setter: UF) -> Self {
221        let getter = RwSignal::<Box<GF>, UnsyncStorage>::new(Box::new(getter));
222        let setter = RwSignal::<Box<UF>, UnsyncStorage>::new(Box::new(setter));
223        DerivedRwSignal {
224            signal,
225            getter,
226            setter,
227            ty: PhantomData,
228            ts: PhantomData,
229        }
230    }
231}
232
233pub fn create_derived_rw_signal<T, O, GF, UF>(
234    signal: RwSignal<T, UnsyncStorage>,
235    getter: GF,
236    setter: UF,
237) -> DerivedRwSignal<T, O, GF, UF>
238where
239    T: 'static,
240    O: 'static,
241    GF: Fn(&T) -> O + Clone + 'static,
242    UF: Fn(&O) -> T + Clone + 'static,
243{
244    DerivedRwSignal::new(signal, getter, setter)
245}
246
247/// A derived signal backed by a thread-safe [`RwSignal`].
248pub struct SyncDerivedRwSignal<
249    T: Send + Sync + 'static,
250    O: Send + Sync,
251    GF: Fn(&T) -> O + Clone + Send + Sync + 'static,
252    UF: Fn(&O) -> T + Clone + Send + Sync + 'static,
253> {
254    signal: RwSignal<T, SyncStorage>,
255    getter: RwSignal<Box<GF>, SyncStorage>,
256    setter: RwSignal<Box<UF>, SyncStorage>,
257    ty: PhantomData<T>,
258    ts: PhantomData<()>,
259}
260
261impl<T, O, GF, UF> Clone for SyncDerivedRwSignal<T, O, GF, UF>
262where
263    T: Send + Sync,
264    O: Send + Sync,
265    GF: Fn(&T) -> O + Copy + Send + Sync,
266    UF: Fn(&O) -> T + Copy + Send + Sync,
267{
268    fn clone(&self) -> Self {
269        *self
270    }
271}
272
273impl<T, O, GF, UF> Copy for SyncDerivedRwSignal<T, O, GF, UF>
274where
275    T: Send + Sync,
276    O: Send + Sync,
277    GF: Fn(&T) -> O + Copy + Send + Sync,
278    UF: Fn(&O) -> T + Copy + Send + Sync,
279{
280}
281
282impl<T, O, GF, UF> SignalGet<O> for SyncDerivedRwSignal<T, O, GF, UF>
283where
284    T: Clone + Send + Sync + 'static,
285    O: Clone + Send + Sync + 'static,
286    GF: Fn(&T) -> O + Copy + Send + Sync,
287    UF: Fn(&O) -> T + Copy + Send + Sync,
288{
289    fn id(&self) -> crate::id::Id {
290        self.signal.id
291    }
292
293    fn get_untracked(&self) -> O
294    where
295        O: 'static,
296    {
297        self.try_get_untracked().unwrap()
298    }
299
300    fn get(&self) -> O
301    where
302        O: 'static,
303    {
304        self.try_get().unwrap()
305    }
306
307    fn try_get(&self) -> Option<O>
308    where
309        O: 'static,
310    {
311        let sig = self.getter;
312        self.signal.id.signal().map(|signal| {
313            let func = sig.get_untracked();
314            func(&signal.get()).clone()
315        })
316    }
317
318    fn try_get_untracked(&self) -> Option<O>
319    where
320        O: 'static,
321    {
322        let sig = self.getter;
323        self.signal.id.signal().map(|signal| {
324            let func = sig.get_untracked();
325            func(&signal.get_untracked()).clone()
326        })
327    }
328}
329
330impl<T, O, GF, UF> SignalWith<O> for SyncDerivedRwSignal<T, O, GF, UF>
331where
332    T: Clone + Send + Sync + 'static,
333    O: Clone + Send + Sync,
334    GF: Fn(&T) -> O + Copy + Send + Sync,
335    UF: Fn(&O) -> T + Copy + Send + Sync,
336{
337    fn id(&self) -> crate::id::Id {
338        self.signal.id
339    }
340
341    fn with<O2>(&self, f: impl FnOnce(&O) -> O2) -> O2
342    where
343        T: 'static,
344    {
345        let func = self.getter.get_untracked();
346        self.signal.id.signal().unwrap().with(|t| f(&func(t)))
347    }
348
349    fn with_untracked<O2>(&self, f: impl FnOnce(&O) -> O2) -> O2
350    where
351        T: 'static,
352    {
353        let func = self.getter.get_untracked();
354        self.signal
355            .id
356            .signal()
357            .unwrap()
358            .with_untracked(|t| f(&func(t)))
359    }
360
361    fn try_with<O2>(&self, f: impl FnOnce(Option<&O>) -> O2) -> O2
362    where
363        T: 'static,
364    {
365        if let Some(signal) = self.signal.id.signal() {
366            let func = self.getter.get_untracked();
367            signal.with(|v| f(Some(&func(v))))
368        } else {
369            f(None)
370        }
371    }
372
373    fn try_with_untracked<O2>(&self, f: impl FnOnce(Option<&O>) -> O2) -> O2
374    where
375        T: 'static,
376    {
377        if let Some(signal) = self.signal.id.signal() {
378            let func = self.getter.get_untracked();
379            signal.with_untracked(|v| f(Some(&func(v))))
380        } else {
381            f(None)
382        }
383    }
384}
385
386impl<T, O, GF, UF> SignalTrack<O> for SyncDerivedRwSignal<T, O, GF, UF>
387where
388    T: Clone + Send + Sync + 'static,
389    O: Clone + Send + Sync,
390    GF: Fn(&T) -> O + Copy + Send + Sync,
391    UF: Fn(&O) -> T + Copy + Send + Sync,
392{
393    fn id(&self) -> crate::id::Id {
394        self.signal.id
395    }
396}
397
398impl<T, O, GF, UF> SignalUpdate<O> for SyncDerivedRwSignal<T, O, GF, UF>
399where
400    T: Send + Sync + 'static,
401    O: Send + Sync + 'static,
402    GF: Fn(&T) -> O + Copy + Send + Sync,
403    UF: Fn(&O) -> T + Copy + Send + Sync,
404{
405    fn id(&self) -> crate::id::Id {
406        self.signal.id
407    }
408
409    fn set(&self, new_value: O)
410    where
411        O: 'static,
412    {
413        if let Some(signal) = self.id().signal() {
414            let func = self.setter.get_untracked();
415            signal.update_value_sync::<_, T>(|v| {
416                let new = func(&new_value);
417                *v = new;
418            });
419        }
420    }
421
422    fn update(&self, f: impl FnOnce(&mut O))
423    where
424        O: 'static,
425    {
426        if let Some(signal) = self.id().signal() {
427            let get_func = self.getter.get_untracked();
428            let set_func = self.setter.get_untracked();
429            signal.update_value_sync::<_, T>(|cv| {
430                let mut new = get_func(cv);
431                f(&mut new);
432                let new = set_func(&new);
433                *cv = new;
434            });
435        }
436    }
437
438    fn try_update<O2>(&self, f: impl FnOnce(&mut O) -> O2) -> Option<O2>
439    where
440        O: 'static,
441    {
442        self.id().signal().map(|signal| {
443            let get_func = self.getter.get_untracked();
444            let set_func = self.setter.get_untracked();
445            signal.update_value_sync::<_, T>(|cv| {
446                let mut new = get_func(cv);
447                let ret = f(&mut new);
448                let new = set_func(&new);
449                *cv = new;
450                ret
451            })
452        })
453    }
454}
455
456impl<T, O, GF, UF> SyncDerivedRwSignal<T, O, GF, UF>
457where
458    T: Send + Sync + 'static,
459    O: Send + Sync,
460    GF: Fn(&T) -> O + Clone + Send + Sync + 'static,
461    UF: Fn(&O) -> T + Clone + Send + Sync + 'static,
462{
463    pub fn new(signal: RwSignal<T, SyncStorage>, getter: GF, setter: UF) -> Self {
464        let getter = RwSignal::<Box<GF>, SyncStorage>::new_sync(Box::new(getter));
465        let setter = RwSignal::<Box<UF>, SyncStorage>::new_sync(Box::new(setter));
466        SyncDerivedRwSignal {
467            signal,
468            getter,
469            setter,
470            ty: PhantomData,
471            ts: PhantomData,
472        }
473    }
474}
475
476pub fn create_sync_derived_rw_signal<T, O, GF, UF>(
477    signal: RwSignal<T, SyncStorage>,
478    getter: GF,
479    setter: UF,
480) -> SyncDerivedRwSignal<T, O, GF, UF>
481where
482    T: Send + Sync + 'static,
483    O: Send + Sync,
484    GF: Fn(&T) -> O + Clone + Send + Sync + 'static,
485    UF: Fn(&O) -> T + Clone + Send + Sync + 'static,
486{
487    SyncDerivedRwSignal::new(signal, getter, setter)
488}