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#[allow(dead_code)]
22pub struct NotThreadSafe(*const ());
23
24pub 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> RwSignal<T> {
57 pub fn read_only(&self) -> ReadSignal<T> {
59 ReadSignal {
60 id: self.id,
61 ty: PhantomData,
62 ts: PhantomData,
63 }
64 }
65
66 pub fn write_only(&self) -> WriteSignal<T> {
68 WriteSignal {
69 id: self.id,
70 ty: PhantomData,
71 ts: PhantomData,
72 }
73 }
74}
75
76impl<T: 'static> RwSignal<T> {
77 pub fn new(value: T) -> Self {
78 create_rw_signal(value)
79 }
80 pub fn new_split(value: T) -> (ReadSignal<T>, WriteSignal<T>) {
81 let sig = Self::new(value);
82 (sig.read_only(), sig.write_only())
83 }
84}
85
86pub fn create_rw_signal<T>(value: T) -> RwSignal<T>
92where
93 T: Any + 'static,
94{
95 let id = Signal::create(value);
96 id.set_scope();
97 RwSignal {
98 id,
99 ty: PhantomData,
100 ts: PhantomData,
101 }
102}
103
104pub struct ReadSignal<T> {
106 pub(crate) id: Id,
107 pub(crate) ty: PhantomData<T>,
108 pub(crate) ts: PhantomData<NotThreadSafe>,
109}
110
111impl<T> Copy for ReadSignal<T> {}
112
113impl<T> Clone for ReadSignal<T> {
114 fn clone(&self) -> Self {
115 *self
116 }
117}
118
119impl<T> Eq for ReadSignal<T> {}
120
121impl<T> PartialEq for ReadSignal<T> {
122 fn eq(&self, other: &Self) -> bool {
123 self.id == other.id
124 }
125}
126
127pub struct WriteSignal<T> {
129 pub(crate) id: Id,
130 pub(crate) ty: PhantomData<T>,
131 pub(crate) ts: PhantomData<NotThreadSafe>,
132}
133
134impl<T> Copy for WriteSignal<T> {}
135
136impl<T> Clone for WriteSignal<T> {
137 fn clone(&self) -> Self {
138 *self
139 }
140}
141
142impl<T> Eq for WriteSignal<T> {}
143
144impl<T> PartialEq for WriteSignal<T> {
145 fn eq(&self, other: &Self) -> bool {
146 self.id == other.id
147 }
148}
149
150pub fn create_signal<T>(value: T) -> (ReadSignal<T>, WriteSignal<T>)
156where
157 T: Any + 'static,
158{
159 let s = create_rw_signal(value);
160 (s.read_only(), s.write_only())
161}
162
163#[derive(Clone)]
165pub(crate) struct Signal {
166 pub(crate) id: Id,
167 pub(crate) value: Rc<dyn Any>,
168 pub(crate) subscribers: Rc<RefCell<HashMap<Id, Rc<dyn EffectTrait>>>>,
169 pub(crate) ts: PhantomData<NotThreadSafe>,
170}
171
172impl Signal {
173 pub fn create<T>(value: T) -> Id
174 where
175 T: Any + 'static,
176 {
177 let id = Id::next();
178 let value = RefCell::new(value);
179 let signal = Signal {
180 id,
181 subscribers: Rc::new(RefCell::new(HashMap::new())),
182 value: Rc::new(value),
183 ts: PhantomData,
184 };
185 id.add_signal(signal);
186 id
187 }
188
189 pub fn borrow<T: 'static>(&self) -> Ref<'_, T> {
190 let value = self
191 .value
192 .downcast_ref::<RefCell<T>>()
193 .expect("to downcast signal type");
194 value.borrow()
195 }
196
197 pub(crate) fn get_untracked<T: Clone + 'static>(&self) -> T {
198 let value = self.borrow::<T>();
199 value.clone()
200 }
201
202 pub(crate) fn get<T: Clone + 'static>(&self) -> T {
203 self.subscribe();
204 self.get_untracked()
205 }
206
207 pub(crate) fn with_untracked<O, T: 'static>(&self, f: impl FnOnce(&T) -> O) -> O {
208 let value = self.borrow::<T>();
209 f(&value)
210 }
211
212 pub(crate) fn with<O, T: 'static>(&self, f: impl FnOnce(&T) -> O) -> O {
213 self.subscribe();
214 self.with_untracked(f)
215 }
216
217 pub(crate) fn update_value<U, T: 'static>(&self, f: impl FnOnce(&mut T) -> U) -> U {
218 let result = self
219 .value
220 .downcast_ref::<RefCell<T>>()
221 .expect("to downcast signal type");
222 let result = f(&mut result.borrow_mut());
223 self.run_effects();
224 result
225 }
226
227 pub(crate) fn subscribers(&self) -> HashMap<Id, Rc<dyn EffectTrait>> {
228 self.subscribers.borrow().clone()
229 }
230
231 pub(crate) fn run_effects(&self) {
232 if RUNTIME.with(|r| r.batching.get()) {
234 RUNTIME.with(|r| {
235 for (_, subscriber) in self.subscribers() {
236 r.add_pending_effect(subscriber);
237 }
238 });
239 return;
240 }
241
242 for (_, subscriber) in self.subscribers() {
243 run_effect(subscriber);
244 }
245 }
246
247 pub(crate) fn subscribe(&self) {
248 RUNTIME.with(|runtime| {
249 if let Some(effect) = runtime.current_effect.borrow().as_ref() {
250 self.subscribers
251 .borrow_mut()
252 .insert(effect.id(), effect.clone());
253 effect.add_observer(self.id);
254 }
255 });
256 }
257}
258
259impl<T: Clone> SignalGet<T> for RwSignal<T> {
260 fn id(&self) -> Id {
261 self.id
262 }
263}
264
265impl<T> SignalWith<T> for RwSignal<T> {
266 fn id(&self) -> Id {
267 self.id
268 }
269}
270
271impl<T> SignalTrack<T> for RwSignal<T> {
272 fn id(&self) -> Id {
273 self.id
274 }
275}
276
277impl<T> SignalRead<T> for RwSignal<T> {
278 fn id(&self) -> Id {
279 self.id
280 }
281}
282
283impl<T> SignalUpdate<T> for RwSignal<T> {
284 fn id(&self) -> Id {
285 self.id
286 }
287}
288
289impl<T> SignalWrite<T> for RwSignal<T> {
290 fn id(&self) -> Id {
291 self.id
292 }
293}
294
295impl<T: Clone> SignalGet<T> for ReadSignal<T> {
296 fn id(&self) -> Id {
297 self.id
298 }
299}
300
301impl<T> SignalWith<T> for ReadSignal<T> {
302 fn id(&self) -> Id {
303 self.id
304 }
305}
306
307impl<T> SignalTrack<T> for ReadSignal<T> {
308 fn id(&self) -> Id {
309 self.id
310 }
311}
312
313impl<T> SignalRead<T> for ReadSignal<T> {
314 fn id(&self) -> Id {
315 self.id
316 }
317}
318
319impl<T> SignalUpdate<T> for WriteSignal<T> {
320 fn id(&self) -> Id {
321 self.id
322 }
323}
324
325impl<T> SignalWrite<T> for WriteSignal<T> {
326 fn id(&self) -> Id {
327 self.id
328 }
329}