1use std::{
2 any::Any,
3 cell::{Ref, RefCell, RefMut},
4 collections::HashSet,
5 fmt,
6 marker::PhantomData,
7 rc::Rc,
8 sync::Arc,
9};
10
11#[cfg(debug_assertions)]
12use std::cell::Cell;
13#[cfg(debug_assertions)]
14use std::panic::Location;
15
16use parking_lot::{Mutex, MutexGuard};
17
18use crate::{
19 id::Id,
20 read::{SignalRead, SignalTrack, SignalWith},
21 runtime::{Runtime, RUNTIME},
22 storage::{Storage, SyncStorage, UnsyncStorage},
23 sync_runtime::{SyncSignal, SYNC_RUNTIME},
24 write::SignalWrite,
25 SignalGet, SignalUpdate,
26};
27
28#[derive(Debug)]
29pub(crate) struct TrackedRefCell<T> {
30 inner: RefCell<T>,
31 #[cfg(debug_assertions)]
32 shared_borrows: Cell<usize>,
33 #[cfg(debug_assertions)]
34 has_mut_borrow: Cell<bool>,
35 #[cfg(debug_assertions)]
36 holder: Cell<Option<&'static Location<'static>>>,
37}
38
39impl<T> TrackedRefCell<T> {
40 #[cfg_attr(debug_assertions, track_caller)]
41 pub(crate) fn new(value: T) -> Self {
42 Self {
43 inner: RefCell::new(value),
44 #[cfg(debug_assertions)]
45 shared_borrows: Cell::new(0),
46 #[cfg(debug_assertions)]
47 has_mut_borrow: Cell::new(false),
48 #[cfg(debug_assertions)]
49 holder: Cell::new(None),
50 }
51 }
52
53 #[cfg_attr(debug_assertions, track_caller)]
54 pub(crate) fn borrow(&self) -> TrackedRef<'_, T> {
55 #[cfg(debug_assertions)]
56 return self.borrow_at(Location::caller());
57 #[cfg(not(debug_assertions))]
58 return TrackedRef {
59 inner: self.inner.borrow(),
60 };
61 }
62
63 #[cfg_attr(debug_assertions, track_caller)]
64 pub(crate) fn borrow_mut(&self) -> TrackedRefMut<'_, T> {
65 #[cfg(debug_assertions)]
66 return self.borrow_mut_at(Location::caller());
67 #[cfg(not(debug_assertions))]
68 return TrackedRefMut {
69 inner: self.inner.borrow_mut(),
70 };
71 }
72
73 #[cfg(debug_assertions)]
74 pub(crate) fn borrow_at(&self, caller: &'static Location<'static>) -> TrackedRef<'_, T> {
75 let inner = self
76 .inner
77 .try_borrow()
78 .unwrap_or_else(|_| self.panic_conflict(caller));
79 let shared = self.shared_borrows.get();
80 if shared == 0 && !self.has_mut_borrow.get() {
81 self.holder.set(Some(caller));
82 }
83 self.shared_borrows.set(shared + 1);
84 TrackedRef { inner, cell: self }
85 }
86
87 #[cfg(debug_assertions)]
88 pub(crate) fn borrow_mut_at(&self, caller: &'static Location<'static>) -> TrackedRefMut<'_, T> {
89 let inner = self
90 .inner
91 .try_borrow_mut()
92 .unwrap_or_else(|_| self.panic_conflict(caller));
93 if self.shared_borrows.get() == 0 && !self.has_mut_borrow.get() {
94 self.holder.set(Some(caller));
95 }
96 self.has_mut_borrow.set(true);
97 TrackedRefMut { inner, cell: self }
98 }
99
100 #[cfg(debug_assertions)]
101 fn release_shared(&self) {
102 let shared = self.shared_borrows.get().saturating_sub(1);
103 self.shared_borrows.set(shared);
104 if shared == 0 && !self.has_mut_borrow.get() {
105 self.holder.set(None);
106 }
107 }
108
109 #[cfg(debug_assertions)]
110 fn release_mut(&self) {
111 self.has_mut_borrow.set(false);
112 if self.shared_borrows.get() == 0 {
113 self.holder.set(None);
114 }
115 }
116
117 #[cfg(debug_assertions)]
118 fn panic_conflict(&self, caller: &'static Location<'static>) -> ! {
119 match self.holder.get() {
120 Some(loc) => panic!(
121 "signal value already borrowed at {}:{} (attempted at {}:{})",
122 loc.file(),
123 loc.line(),
124 caller.file(),
125 caller.line()
126 ),
127 None => panic!(
128 "signal value already borrowed (attempted at {}:{})",
129 caller.file(),
130 caller.line()
131 ),
132 }
133 }
134}
135
136pub struct TrackedRef<'a, T> {
137 inner: Ref<'a, T>,
138 #[cfg(debug_assertions)]
139 cell: &'a TrackedRefCell<T>,
140}
141
142impl<'a, T> Drop for TrackedRef<'a, T> {
143 fn drop(&mut self) {
144 #[cfg(debug_assertions)]
145 self.cell.release_shared();
146 }
147}
148
149impl<'a, T> std::ops::Deref for TrackedRef<'a, T> {
150 type Target = T;
151 fn deref(&self) -> &Self::Target {
152 &self.inner
153 }
154}
155
156pub struct TrackedRefMut<'a, T> {
157 inner: RefMut<'a, T>,
158 #[cfg(debug_assertions)]
159 cell: &'a TrackedRefCell<T>,
160}
161
162impl<'a, T> Drop for TrackedRefMut<'a, T> {
163 fn drop(&mut self) {
164 #[cfg(debug_assertions)]
165 self.cell.release_mut();
166 }
167}
168
169impl<'a, T> std::ops::Deref for TrackedRefMut<'a, T> {
170 type Target = T;
171 fn deref(&self) -> &Self::Target {
172 &self.inner
173 }
174}
175
176impl<'a, T> std::ops::DerefMut for TrackedRefMut<'a, T> {
177 fn deref_mut(&mut self) -> &mut Self::Target {
178 &mut self.inner
179 }
180}
181
182pub type SyncRwSignal<T> = RwSignal<T, SyncStorage>;
183pub type SyncReadSignal<T> = ReadSignal<T, SyncStorage>;
184pub type SyncWriteSignal<T> = WriteSignal<T, SyncStorage>;
185
186impl<T, S> SignalTrack<T> for RwSignal<T, S> {
187 fn id(&self) -> Id {
188 self.id
189 }
190}
191
192impl<T, S> SignalTrack<T> for ReadSignal<T, S> {
193 fn id(&self) -> Id {
194 self.id
195 }
196}
197
198impl<T: Any + 'static> Storage<T> for UnsyncStorage {
199 fn create(value: T) -> Id {
200 SignalState::new(value)
201 }
202
203 fn get(id: Id) -> Option<Self::Signal> {
204 id.signal()
205 }
206
207 type Signal = SignalState;
208}
209
210impl<T: Any + Send + Sync + 'static> Storage<T> for SyncStorage {
211 fn create(value: T) -> Id {
212 SignalState::new_sync(value)
213 }
214
215 fn get(id: Id) -> Option<Self::Signal> {
216 id.signal()
217 .or_else(|| SYNC_RUNTIME.get_signal(&id).map(|s| s.into()))
218 }
219
220 type Signal = SignalState;
221}
222
223pub struct RwSignal<T, S = UnsyncStorage> {
225 pub(crate) id: Id,
226 pub(crate) ty: PhantomData<T>,
227 pub(crate) st: PhantomData<S>,
228}
229
230impl<T, S> RwSignal<T, S> {
231 pub fn id(&self) -> Id {
232 self.id
233 }
234}
235
236impl<T, S> Copy for RwSignal<T, S> {}
237
238impl<T, S> Clone for RwSignal<T, S> {
239 fn clone(&self) -> Self {
240 *self
241 }
242}
243
244impl<T, S> Eq for RwSignal<T, S> {}
245
246impl<T, S> PartialEq for RwSignal<T, S> {
247 fn eq(&self, other: &Self) -> bool {
248 self.id == other.id
249 }
250}
251
252impl<T, S> fmt::Debug for RwSignal<T, S> {
253 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
254 let mut s = f.debug_struct("RwSignal");
255 s.field("id", &self.id);
256 s.field("ty", &self.ty);
257 s.finish()
258 }
259}
260
261impl<T: Default + 'static> Default for RwSignal<T> {
262 fn default() -> Self {
263 RwSignal::new(T::default())
264 }
265}
266
267impl<T, S> RwSignal<T, S> {
268 pub fn read_only(&self) -> ReadSignal<T, S> {
270 ReadSignal {
271 id: self.id,
272 ty: PhantomData,
273 st: PhantomData,
274 }
275 }
276
277 pub fn write_only(&self) -> WriteSignal<T, S> {
279 WriteSignal {
280 id: self.id,
281 ty: PhantomData,
282 st: PhantomData,
283 }
284 }
285}
286
287impl<T: Send + Sync + 'static> RwSignal<T, SyncStorage> {
288 pub fn new_sync(value: T) -> Self {
291 let id = SignalState::new_sync(value);
292 if Runtime::is_ui_thread() {
293 id.set_scope();
294 }
295 RwSignal {
296 id,
297 ty: PhantomData,
298 st: PhantomData,
299 }
300 }
301 pub fn new_sync_split(value: T) -> (ReadSignal<T, SyncStorage>, WriteSignal<T, SyncStorage>) {
304 let sig = Self::new_sync(value);
305 (sig.read_only(), sig.write_only())
306 }
307}
308
309impl<T: 'static> RwSignal<T, UnsyncStorage> {
310 #[cfg_attr(debug_assertions, track_caller)]
311 pub fn new(value: T) -> Self {
312 Runtime::assert_ui_thread();
313 let id = <UnsyncStorage as Storage<T>>::create(value);
314 id.set_scope();
315 RwSignal {
316 id,
317 ty: PhantomData,
318 st: PhantomData,
319 }
320 }
321 #[cfg_attr(debug_assertions, track_caller)]
322 pub fn new_split(value: T) -> (ReadSignal<T, UnsyncStorage>, WriteSignal<T, UnsyncStorage>) {
323 let sig = Self::new(value);
324 (sig.read_only(), sig.write_only())
325 }
326}
327
328#[deprecated(
334 since = "0.2.0",
335 note = "Use RwSignal::new for sync signals or RwSignal::new_local for local ones"
336)]
337#[cfg_attr(debug_assertions, track_caller)]
338pub fn create_rw_signal<T>(value: T) -> RwSignal<T>
339where
340 T: Any + 'static,
341{
342 RwSignal::new(value)
343}
344
345pub struct ReadSignal<T, S = UnsyncStorage> {
347 pub(crate) id: Id,
348 pub(crate) ty: PhantomData<T>,
349 pub(crate) st: PhantomData<S>,
350}
351
352impl<T, S> ReadSignal<T, S> {
353 pub fn id(&self) -> Id {
354 self.id
355 }
356}
357
358impl<T, S> Copy for ReadSignal<T, S> {}
359
360impl<T, S> Clone for ReadSignal<T, S> {
361 fn clone(&self) -> Self {
362 *self
363 }
364}
365
366impl<T, S> Eq for ReadSignal<T, S> {}
367
368impl<T, S> PartialEq for ReadSignal<T, S> {
369 fn eq(&self, other: &Self) -> bool {
370 self.id == other.id
371 }
372}
373
374pub struct WriteSignal<T, S = UnsyncStorage> {
376 pub(crate) id: Id,
377 pub(crate) ty: PhantomData<T>,
378 pub(crate) st: PhantomData<S>,
379}
380
381impl<T, S> WriteSignal<T, S> {
382 pub fn id(&self) -> Id {
383 self.id
384 }
385}
386
387impl<T, S> Copy for WriteSignal<T, S> {}
388
389impl<T, S> Clone for WriteSignal<T, S> {
390 fn clone(&self) -> Self {
391 *self
392 }
393}
394
395impl<T, S> Eq for WriteSignal<T, S> {}
396
397impl<T, S> PartialEq for WriteSignal<T, S> {
398 fn eq(&self, other: &Self) -> bool {
399 self.id == other.id
400 }
401}
402
403#[deprecated(
409 since = "0.2.0",
410 note = "Use RwSignal::new for sync signals or RwSignal::new_local for local ones"
411)]
412pub fn create_signal<T>(value: T) -> (ReadSignal<T, UnsyncStorage>, WriteSignal<T, UnsyncStorage>)
413where
414 T: Any + 'static,
415{
416 let id = SignalState::new(value);
417 (
418 ReadSignal {
419 id,
420 ty: PhantomData,
421 st: PhantomData,
422 },
423 WriteSignal {
424 id,
425 ty: PhantomData,
426 st: PhantomData,
427 },
428 )
429}
430
431#[derive(Clone)]
433pub(crate) struct SignalState {
434 pub(crate) id: Id,
435 pub(crate) value: SignalValue,
436 pub(crate) subscribers: Arc<Mutex<HashSet<Id>>>,
437}
438
439#[derive(Clone)]
440pub(crate) enum SignalValue {
441 Sync(Arc<dyn Any + Send + Sync>),
442 Local(Rc<dyn Any>),
443}
444
445#[allow(dead_code)]
446pub enum SignalBorrow<'a, T> {
447 Sync(MutexGuard<'a, T>),
448 Local(TrackedRef<'a, T>),
449}
450
451impl SignalState {
452 #[allow(clippy::new_ret_no_self)]
453 #[cfg_attr(debug_assertions, track_caller)]
454 pub fn new<T>(value: T) -> Id
455 where
456 T: Any + 'static,
457 {
458 Runtime::assert_ui_thread();
459 let id = Id::next();
460 let value = TrackedRefCell::new(value);
461 let signal = SignalState {
462 id,
463 subscribers: Arc::new(Mutex::new(HashSet::new())),
464 value: SignalValue::Local(Rc::new(value)),
465 };
466 id.add_signal(signal);
467 id
468 }
469
470 pub fn new_sync<T>(value: T) -> Id
471 where
472 T: Any + Send + Sync + 'static,
473 {
474 let id = Id::next();
475 let value = Arc::new(Mutex::new(value));
476 let subscribers = Arc::new(Mutex::new(HashSet::new()));
477 SYNC_RUNTIME.insert_signal(
479 id,
480 SyncSignal {
481 id,
482 value,
483 subscribers,
484 },
485 );
486 id
487 }
488
489 #[deprecated(
490 since = "0.2.0",
491 note = "Use SignalState::new_sync for sync signals or SignalState::new for local ones"
492 )]
493 #[allow(dead_code)]
494 pub fn create<T>(value: T) -> Id
495 where
496 T: Any + Send + Sync + 'static,
497 {
498 Self::new_sync(value)
499 }
500
501 #[allow(dead_code)]
502 #[cfg_attr(debug_assertions, track_caller)]
503 pub fn borrow<T: 'static>(&self) -> SignalBorrow<'_, T> {
504 match &self.value {
505 SignalValue::Sync(v) => {
506 let v = v
507 .as_ref()
508 .downcast_ref::<Mutex<T>>()
509 .expect("to downcast signal type");
510 SignalBorrow::Sync(v.lock())
511 }
512 SignalValue::Local(v) => {
513 let v = v
514 .as_ref()
515 .downcast_ref::<TrackedRefCell<T>>()
516 .expect("to downcast signal type");
517 #[cfg(debug_assertions)]
518 {
519 SignalBorrow::Local(v.borrow_at(Location::caller()))
520 }
521 #[cfg(not(debug_assertions))]
522 {
523 SignalBorrow::Local(v.borrow())
524 }
525 }
526 }
527 }
528
529 #[cfg_attr(debug_assertions, track_caller)]
530 pub(crate) fn get_untracked<T: Clone + 'static>(&self) -> T {
531 match &self.value {
532 SignalValue::Sync(v) => {
533 let v = v
534 .as_ref()
535 .downcast_ref::<Mutex<T>>()
536 .expect("to downcast signal type");
537 v.lock().clone()
538 }
539 SignalValue::Local(v) => {
540 let v = v
541 .as_ref()
542 .downcast_ref::<TrackedRefCell<T>>()
543 .expect("to downcast signal type");
544 #[cfg(debug_assertions)]
545 {
546 v.borrow_at(Location::caller()).clone()
547 }
548 #[cfg(not(debug_assertions))]
549 {
550 v.borrow().clone()
551 }
552 }
553 }
554 }
555
556 #[cfg_attr(debug_assertions, track_caller)]
557 pub(crate) fn get<T: Clone + 'static>(&self) -> T {
558 self.subscribe();
559 self.get_untracked()
560 }
561
562 #[cfg_attr(debug_assertions, track_caller)]
563 pub(crate) fn with_untracked<O, T: 'static>(&self, f: impl FnOnce(&T) -> O) -> O {
564 match &self.value {
565 SignalValue::Sync(v) => {
566 let v = v
567 .as_ref()
568 .downcast_ref::<Mutex<T>>()
569 .expect("to downcast signal type");
570 f(&v.lock())
571 }
572 SignalValue::Local(v) => {
573 let v = v
574 .as_ref()
575 .downcast_ref::<TrackedRefCell<T>>()
576 .expect("to downcast signal type");
577 #[cfg(debug_assertions)]
578 {
579 f(&v.borrow_at(Location::caller()))
580 }
581 #[cfg(not(debug_assertions))]
582 {
583 f(&v.borrow())
584 }
585 }
586 }
587 }
588
589 #[cfg_attr(debug_assertions, track_caller)]
590 pub(crate) fn with<O, T: 'static>(&self, f: impl FnOnce(&T) -> O) -> O {
591 self.subscribe();
592 self.with_untracked(f)
593 }
594
595 pub(crate) fn update_value_sync<U, T: Send + Sync + 'static>(
596 &self,
597 f: impl FnOnce(&mut T) -> U,
598 ) -> U {
599 let value = self.as_sync::<T>();
600 let mut guard = value.lock();
601 let result = f(&mut *guard);
602 drop(guard);
603 self.run_effects();
604 result
605 }
606
607 #[cfg_attr(debug_assertions, track_caller)]
608 pub(crate) fn update_value_local<U, T: 'static>(&self, f: impl FnOnce(&mut T) -> U) -> U {
609 let value = self.as_local::<T>();
610 #[cfg(debug_assertions)]
611 let mut guard = value.borrow_mut_at(Location::caller());
612 #[cfg(not(debug_assertions))]
613 let mut guard = value.borrow_mut();
614 let result = f(&mut *guard);
615 drop(guard);
616 self.run_effects();
617 result
618 }
619
620 pub(crate) fn subscriber_ids(&self) -> HashSet<Id> {
621 self.subscribers.lock().iter().copied().collect()
622 }
623
624 pub(crate) fn run_effects(&self) {
625 let ids: Vec<_> = self.subscriber_ids().into_iter().collect();
626 let on_ui_thread = Runtime::is_ui_thread();
627
628 if !on_ui_thread {
629 SYNC_RUNTIME.enqueue_effects(ids);
630 return;
631 }
632
633 RUNTIME.with(|r| {
634 for id in &ids {
635 r.add_pending_effect(*id);
636 }
637 if !r.batching.get() {
638 r.run_pending_effects();
639 }
640 });
641 }
642
643 pub(crate) fn subscribe(&self) {
644 RUNTIME.with(|runtime| {
645 if let Some(effect) = runtime.current_effect.borrow().as_ref() {
646 self.subscribers.lock().insert(effect.id());
647 effect.add_observer(self.id);
648 }
649 });
650 }
651
652 pub(crate) fn as_sync<T: Send + Sync + 'static>(&self) -> Arc<Mutex<T>> {
653 match &self.value {
654 SignalValue::Sync(v) => v
655 .clone()
656 .downcast::<Mutex<T>>()
657 .expect("to downcast signal type"),
658 SignalValue::Local(_) => unreachable!("expected sync signal storage"),
659 }
660 }
661
662 pub(crate) fn as_local<T: 'static>(&self) -> Rc<TrackedRefCell<T>> {
663 match &self.value {
664 SignalValue::Local(v) => v
665 .clone()
666 .downcast::<TrackedRefCell<T>>()
667 .expect("to downcast signal type"),
668 SignalValue::Sync(_) => unreachable!("expected local signal storage"),
669 }
670 }
671}
672
673impl<T: Clone + Send + Sync> SignalGet<T> for RwSignal<T, SyncStorage> {
675 fn id(&self) -> Id {
676 self.id
677 }
678}
679
680impl<T: Send + Sync> SignalWith<T> for RwSignal<T, SyncStorage> {
681 fn id(&self) -> Id {
682 self.id
683 }
684}
685
686impl<T: Send + Sync> SignalRead<T> for RwSignal<T, SyncStorage> {
687 fn id(&self) -> Id {
688 self.id
689 }
690
691 fn try_read(&self) -> Option<crate::read::ReadRef<'_, T>>
692 where
693 T: 'static,
694 {
695 self.id().signal().map(|signal| {
696 signal.subscribe();
697 crate::read::ReadRef::Sync(crate::read::SyncReadRef::new(signal.as_sync::<T>()))
698 })
699 }
700
701 fn try_read_untracked(&self) -> Option<crate::read::ReadRef<'_, T>>
702 where
703 T: 'static,
704 {
705 self.id().signal().map(|signal| {
706 crate::read::ReadRef::Sync(crate::read::SyncReadRef::new(signal.as_sync::<T>()))
707 })
708 }
709}
710
711impl<T: Send + Sync> SignalUpdate<T> for RwSignal<T, SyncStorage> {
712 fn id(&self) -> Id {
713 self.id
714 }
715
716 fn set(&self, new_value: T)
717 where
718 T: 'static,
719 {
720 if let Some(signal) = self.id().signal() {
721 signal.update_value_sync(|v| *v = new_value);
722 }
723 }
724
725 fn update(&self, f: impl FnOnce(&mut T))
726 where
727 T: 'static,
728 {
729 if let Some(signal) = self.id().signal() {
730 signal.update_value_sync(f);
731 }
732 }
733
734 fn try_update<O>(&self, f: impl FnOnce(&mut T) -> O) -> Option<O>
735 where
736 T: 'static,
737 {
738 self.id().signal().map(|signal| signal.update_value_sync(f))
739 }
740}
741
742impl<T: Send + Sync> SignalWrite<T> for RwSignal<T, SyncStorage> {
743 fn id(&self) -> Id {
744 self.id
745 }
746
747 fn write(&self) -> crate::write::WriteRef<'_, T>
748 where
749 T: 'static,
750 {
751 self.try_write().unwrap()
752 }
753
754 fn try_write(&self) -> Option<crate::write::WriteRef<'_, T>>
755 where
756 T: 'static,
757 {
758 self.id().signal().map(|signal| {
759 crate::write::WriteRef::Sync(crate::write::SyncWriteRef::new(
760 signal.id,
761 signal.as_sync::<T>(),
762 ))
763 })
764 }
765}
766
767impl<T: Clone + Send + Sync> SignalGet<T> for ReadSignal<T, SyncStorage> {
768 fn id(&self) -> Id {
769 self.id
770 }
771}
772
773impl<T: Send + Sync> SignalWith<T> for ReadSignal<T, SyncStorage> {
774 fn id(&self) -> Id {
775 self.id
776 }
777}
778
779impl<T: Send + Sync> SignalRead<T> for ReadSignal<T, SyncStorage> {
780 fn id(&self) -> Id {
781 self.id
782 }
783
784 fn try_read(&self) -> Option<crate::read::ReadRef<'_, T>>
785 where
786 T: 'static,
787 {
788 self.id().signal().map(|signal| {
789 signal.subscribe();
790 crate::read::ReadRef::Sync(crate::read::SyncReadRef::new(signal.as_sync::<T>()))
791 })
792 }
793
794 fn try_read_untracked(&self) -> Option<crate::read::ReadRef<'_, T>>
795 where
796 T: 'static,
797 {
798 self.id().signal().map(|signal| {
799 crate::read::ReadRef::Sync(crate::read::SyncReadRef::new(signal.as_sync::<T>()))
800 })
801 }
802}
803
804impl<T: Send + Sync> SignalUpdate<T> for WriteSignal<T, SyncStorage> {
805 fn id(&self) -> Id {
806 self.id
807 }
808
809 fn set(&self, new_value: T)
810 where
811 T: 'static,
812 {
813 if let Some(signal) = self.id().signal() {
814 signal.update_value_sync(|v| *v = new_value);
815 }
816 }
817
818 fn update(&self, f: impl FnOnce(&mut T))
819 where
820 T: 'static,
821 {
822 if let Some(signal) = self.id().signal() {
823 signal.update_value_sync(f);
824 }
825 }
826
827 fn try_update<O>(&self, f: impl FnOnce(&mut T) -> O) -> Option<O>
828 where
829 T: 'static,
830 {
831 self.id().signal().map(|signal| signal.update_value_sync(f))
832 }
833}
834
835impl<T: Send + Sync> SignalWrite<T> for WriteSignal<T, SyncStorage> {
836 fn id(&self) -> Id {
837 self.id
838 }
839
840 fn try_write(&self) -> Option<crate::write::WriteRef<'_, T>>
841 where
842 T: 'static,
843 {
844 self.id().signal().map(|signal| {
845 crate::write::WriteRef::Sync(crate::write::SyncWriteRef::new(
846 signal.id,
847 signal.as_sync::<T>(),
848 ))
849 })
850 }
851}
852
853impl<T: Clone> SignalGet<T> for RwSignal<T, UnsyncStorage> {
855 fn id(&self) -> Id {
856 self.id
857 }
858}
859
860impl<T> SignalWith<T> for RwSignal<T, UnsyncStorage> {
861 fn id(&self) -> Id {
862 self.id
863 }
864}
865
866impl<T> SignalRead<T> for RwSignal<T, UnsyncStorage> {
867 fn id(&self) -> Id {
868 self.id
869 }
870
871 #[cfg_attr(debug_assertions, track_caller)]
872 fn try_read(&self) -> Option<crate::read::ReadRef<'_, T>>
873 where
874 T: 'static,
875 {
876 Runtime::assert_ui_thread();
877 self.id().signal().map(|signal| {
878 signal.subscribe();
879 crate::read::ReadRef::Local(crate::read::LocalReadRef::new(signal.as_local::<T>()))
880 })
881 }
882
883 fn try_read_untracked(&self) -> Option<crate::read::ReadRef<'_, T>>
884 where
885 T: 'static,
886 {
887 Runtime::assert_ui_thread();
888 self.id().signal().map(|signal| {
889 crate::read::ReadRef::Local(crate::read::LocalReadRef::new(signal.as_local::<T>()))
890 })
891 }
892}
893
894impl<T> SignalUpdate<T> for RwSignal<T, UnsyncStorage> {
895 fn id(&self) -> Id {
896 self.id
897 }
898
899 #[cfg_attr(debug_assertions, track_caller)]
900 fn set(&self, new_value: T)
901 where
902 T: 'static,
903 {
904 Runtime::assert_ui_thread();
905 if let Some(signal) = self.id().signal() {
906 signal.update_value_local(|v| *v = new_value);
907 }
908 }
909
910 #[cfg_attr(debug_assertions, track_caller)]
911 fn update(&self, f: impl FnOnce(&mut T))
912 where
913 T: 'static,
914 {
915 Runtime::assert_ui_thread();
916 if let Some(signal) = self.id().signal() {
917 signal.update_value_local(f);
918 }
919 }
920
921 #[cfg_attr(debug_assertions, track_caller)]
922 fn try_update<O>(&self, f: impl FnOnce(&mut T) -> O) -> Option<O>
923 where
924 T: 'static,
925 {
926 Runtime::assert_ui_thread();
927 self.id()
928 .signal()
929 .map(|signal| signal.update_value_local(f))
930 }
931}
932
933impl<T> SignalWrite<T> for RwSignal<T, UnsyncStorage> {
934 fn id(&self) -> Id {
935 self.id
936 }
937
938 #[cfg_attr(debug_assertions, track_caller)]
939 fn write(&self) -> crate::write::WriteRef<'_, T>
940 where
941 T: 'static,
942 {
943 Runtime::assert_ui_thread();
944 self.try_write().unwrap()
945 }
946
947 #[cfg_attr(debug_assertions, track_caller)]
948 fn try_write(&self) -> Option<crate::write::WriteRef<'_, T>>
949 where
950 T: 'static,
951 {
952 Runtime::assert_ui_thread();
953 self.id().signal().map(|signal| {
954 crate::write::WriteRef::Local(crate::write::LocalWriteRef::new(
955 signal.id,
956 signal.as_local::<T>(),
957 ))
958 })
959 }
960}
961
962impl<T> SignalUpdate<T> for WriteSignal<T, UnsyncStorage> {
963 fn id(&self) -> Id {
964 self.id
965 }
966
967 #[cfg_attr(debug_assertions, track_caller)]
968 fn set(&self, new_value: T)
969 where
970 T: 'static,
971 {
972 Runtime::assert_ui_thread();
973 if let Some(signal) = self.id().signal() {
974 signal.update_value_local(|v| *v = new_value);
975 }
976 }
977
978 #[cfg_attr(debug_assertions, track_caller)]
979 fn update(&self, f: impl FnOnce(&mut T))
980 where
981 T: 'static,
982 {
983 Runtime::assert_ui_thread();
984 if let Some(signal) = self.id().signal() {
985 signal.update_value_local(f);
986 }
987 }
988
989 #[cfg_attr(debug_assertions, track_caller)]
990 fn try_update<O>(&self, f: impl FnOnce(&mut T) -> O) -> Option<O>
991 where
992 T: 'static,
993 {
994 Runtime::assert_ui_thread();
995 self.id()
996 .signal()
997 .map(|signal| signal.update_value_local(f))
998 }
999}
1000
1001impl<T> SignalWrite<T> for WriteSignal<T, UnsyncStorage> {
1002 fn id(&self) -> Id {
1003 self.id
1004 }
1005
1006 #[cfg_attr(debug_assertions, track_caller)]
1007 fn try_write(&self) -> Option<crate::write::WriteRef<'_, T>>
1008 where
1009 T: 'static,
1010 {
1011 Runtime::assert_ui_thread();
1012 self.id().signal().map(|signal| {
1013 crate::write::WriteRef::Local(crate::write::LocalWriteRef::new(
1014 signal.id,
1015 signal.as_local::<T>(),
1016 ))
1017 })
1018 }
1019}
1020
1021impl<T: Clone> SignalGet<T> for ReadSignal<T, UnsyncStorage> {
1022 fn id(&self) -> Id {
1023 self.id
1024 }
1025}
1026
1027impl<T> SignalWith<T> for ReadSignal<T, UnsyncStorage> {
1028 fn id(&self) -> Id {
1029 self.id
1030 }
1031}
1032
1033impl<T> SignalRead<T> for ReadSignal<T, UnsyncStorage> {
1034 fn id(&self) -> Id {
1035 self.id
1036 }
1037
1038 #[cfg_attr(debug_assertions, track_caller)]
1039 fn try_read(&self) -> Option<crate::read::ReadRef<'_, T>>
1040 where
1041 T: 'static,
1042 {
1043 Runtime::assert_ui_thread();
1044 self.id().signal().map(|signal| {
1045 signal.subscribe();
1046 crate::read::ReadRef::Local(crate::read::LocalReadRef::new(signal.as_local::<T>()))
1047 })
1048 }
1049
1050 fn try_read_untracked(&self) -> Option<crate::read::ReadRef<'_, T>>
1051 where
1052 T: 'static,
1053 {
1054 Runtime::assert_ui_thread();
1055 self.id().signal().map(|signal| {
1056 crate::read::ReadRef::Local(crate::read::LocalReadRef::new(signal.as_local::<T>()))
1057 })
1058 }
1059}