1use std::marker::PhantomData;
2
3use crate::{
4 read::SignalTrack, signal::NotThreadSafe, RwSignal, SignalGet, SignalUpdate, SignalWith,
5};
6
7pub struct DerivedRwSignal<
13 T: 'static,
14 O,
15 GF: Fn(&T) -> O + Clone + 'static,
16 UF: Fn(&O) -> T + 'static,
17> {
18 signal: RwSignal<T>,
19 getter: RwSignal<Box<GF>>,
20 setter: RwSignal<Box<UF>>,
21 ty: PhantomData<T>,
22 ts: PhantomData<NotThreadSafe>,
23}
24
25impl<T, O, GF: Fn(&T) -> O + Copy, UF: Fn(&O) -> T + Copy> Clone for DerivedRwSignal<T, O, GF, UF> {
26 fn clone(&self) -> Self {
27 *self
28 }
29}
30
31impl<T, O, GF: Fn(&T) -> O + Copy, UF: Fn(&O) -> T + Copy> Copy for DerivedRwSignal<T, O, GF, UF> {}
32
33impl<T: Clone + 'static, O: Clone, GF: Fn(&T) -> O + Copy, UF: Fn(&O) -> T + Copy> SignalGet<O>
34 for DerivedRwSignal<T, O, GF, UF>
35{
36 fn id(&self) -> crate::id::Id {
37 self.signal.id
38 }
39
40 fn try_get(&self) -> Option<O>
41 where
42 O: 'static,
43 {
44 let sig = self.getter;
45 SignalGet::id(self).signal().map(|signal| {
46 let func = sig.get_untracked();
47 func(&signal.get()).clone()
48 })
49 }
50
51 fn try_get_untracked(&self) -> Option<O>
52 where
53 O: 'static,
54 {
55 let sig = self.getter;
56 SignalGet::id(self).signal().map(|signal| {
57 let func = sig.get_untracked();
58 func(&signal.get_untracked()).clone()
59 })
60 }
61}
62
63impl<T: Clone + 'static, O: Clone, GF: Fn(&T) -> O + Copy, UF: Fn(&O) -> T + Copy> SignalWith<O>
64 for DerivedRwSignal<T, O, GF, UF>
65{
66 fn id(&self) -> crate::id::Id {
67 self.signal.id
68 }
69
70 fn with<O2>(&self, f: impl FnOnce(&O) -> O2) -> O2
71 where
72 T: 'static,
73 {
74 let func = self.getter.get_untracked();
75 SignalWith::id(self).signal().unwrap().with(|t| f(&func(t)))
76 }
77
78 fn with_untracked<O2>(&self, f: impl FnOnce(&O) -> O2) -> O2
79 where
80 T: 'static,
81 {
82 let func = self.getter.get_untracked();
83 SignalWith::id(self)
84 .signal()
85 .unwrap()
86 .with_untracked(|t| f(&func(t)))
87 }
88
89 fn try_with<O2>(&self, f: impl FnOnce(Option<&O>) -> O2) -> O2
90 where
91 T: 'static,
92 {
93 if let Some(signal) = SignalWith::id(self).signal() {
94 let func = self.getter.get_untracked();
95 signal.with(|v| f(Some(&func(v))))
96 } else {
97 f(None)
98 }
99 }
100
101 fn try_with_untracked<O2>(&self, f: impl FnOnce(Option<&O>) -> O2) -> O2
102 where
103 T: 'static,
104 {
105 if let Some(signal) = SignalWith::id(self).signal() {
106 let func = self.getter.get_untracked();
107 signal.with_untracked(|v| f(Some(&func(v))))
108 } else {
109 f(None)
110 }
111 }
112}
113
114impl<T: Clone + 'static, O: Clone, GF: Fn(&T) -> O + Copy, UF: Fn(&O) -> T + Copy> SignalTrack<O>
115 for DerivedRwSignal<T, O, GF, UF>
116{
117 fn id(&self) -> crate::id::Id {
118 self.signal.id
119 }
120 fn track(&self) {
121 SignalWith::id(self).signal().unwrap().subscribe();
122 }
123
124 fn try_track(&self) {
125 if let Some(signal) = SignalWith::id(self).signal() {
126 signal.subscribe();
127 }
128 }
129}
130
131impl<T: 'static, O, GF: Fn(&T) -> O + Copy, UF: Fn(&O) -> T + Copy> SignalUpdate<O>
132 for DerivedRwSignal<T, O, GF, UF>
133{
134 fn id(&self) -> crate::id::Id {
135 self.signal.id
136 }
137
138 fn set(&self, new_value: O)
139 where
140 O: 'static,
141 {
142 if let Some(signal) = self.id().signal() {
143 let func = self.setter.get_untracked();
144 signal.update_value::<_, T>(|v| {
145 let new = func(&new_value);
146 *v = new;
147 });
148 }
149 }
150
151 fn update(&self, f: impl FnOnce(&mut O))
152 where
153 O: 'static,
154 {
155 if let Some(signal) = self.id().signal() {
156 let get_func = self.getter.get_untracked();
157 let set_func = self.setter.get_untracked();
158 signal.update_value::<_, T>(|cv| {
159 let mut new = get_func(cv);
160 f(&mut new);
161 let new = set_func(&new);
162 *cv = new;
163 });
164 }
165 }
166
167 fn try_update<O2>(&self, f: impl FnOnce(&mut O) -> O2) -> Option<O2>
168 where
169 O: 'static,
170 {
171 self.id().signal().map(|signal| {
172 let get_func = self.getter.get_untracked();
173 let set_func = self.setter.get_untracked();
174 signal.update_value::<_, T>(|cv| {
175 let mut new = get_func(cv);
176 let ret = f(&mut new);
177 let new = set_func(&new);
178 *cv = new;
179 ret
180 })
181 })
182 }
183}
184impl<T, O, GF, UF> DerivedRwSignal<T, O, GF, UF>
185where
186 GF: Fn(&T) -> O + Clone + 'static,
187 UF: Fn(&O) -> T + 'static,
188{
189 pub fn new(signal: RwSignal<T>, getter: GF, setter: UF) -> Self {
190 let getter = RwSignal::new(Box::new(getter));
191 let setter = RwSignal::new(Box::new(setter));
192 DerivedRwSignal {
193 signal,
194 getter,
195 setter,
196 ty: PhantomData,
197 ts: PhantomData,
198 }
199 }
200}
201
202pub fn create_derived_rw_signal<T, O, GF, UF>(
203 signal: RwSignal<T>,
204 getter: GF,
205 setter: UF,
206) -> DerivedRwSignal<T, O, GF, UF>
207where
208 GF: Fn(&T) -> O + Clone + 'static,
209 UF: Fn(&O) -> T + 'static,
210{
211 let getter = RwSignal::new(Box::new(getter));
212 let setter = RwSignal::new(Box::new(setter));
213 DerivedRwSignal {
214 signal,
215 getter,
216 setter,
217 ty: PhantomData,
218 ts: PhantomData,
219 }
220}