1use std::marker::PhantomData;
2
3use crate::{
4 storage::{SyncStorage, UnsyncStorage},
5 RwSignal, SignalGet, SignalTrack, SignalUpdate, SignalWith,
6};
7
8pub 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
247pub 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}