1use std::cell::RefCell;
2use std::rc::Rc;
3use std::sync::atomic::{AtomicUsize, Ordering};
4
5use crate::reactive;
6
7pub type SubId = usize;
8
9static NEXT_SIGNAL_ID: AtomicUsize = AtomicUsize::new(1);
10
11pub struct Signal<T: 'static>(Rc<RefCell<Inner<T>>>);
12
13impl<T> Clone for Signal<T> {
14 fn clone(&self) -> Self {
15 Self(self.0.clone())
16 }
17}
18
19struct Inner<T> {
20 id: usize,
21 value: T,
22 subs: Vec<Option<Box<dyn Fn(&T)>>>,
23}
24
25impl<T> Signal<T> {
26 pub fn new(value: T) -> Self {
27 let id = NEXT_SIGNAL_ID.fetch_add(1, Ordering::Relaxed);
28 Self(Rc::new(RefCell::new(Inner {
29 id,
30 value,
31 subs: Vec::new(),
32 })))
33 }
34
35 pub fn id(&self) -> usize {
36 self.0.borrow().id
37 }
38
39 pub fn get(&self) -> T
40 where
41 T: Clone,
42 {
43 let inner = self.0.borrow();
44 reactive::register_signal_read(inner.id);
45 inner.value.clone()
46 }
47
48 pub fn with<R>(&self, f: impl FnOnce(&T) -> R) -> R {
51 let inner = self.0.borrow();
52 reactive::register_signal_read(inner.id);
53 f(&inner.value)
54 }
55
56 pub fn set_neq(&self, v: T)
59 where
60 T: PartialEq,
61 {
62 let id = {
63 let mut inner = self.0.borrow_mut();
64 if inner.value == v {
65 return;
66 }
67 inner.value = v;
68 inner.id
69 };
70 self.notify_and_request_frame(id);
71 }
72
73 pub fn set(&self, v: T) {
75 let id = {
76 let mut inner = self.0.borrow_mut();
77 inner.value = v;
78 inner.id
79 };
80 self.notify_and_request_frame(id);
81 }
82
83 pub fn update<F: FnOnce(&mut T)>(&self, f: F) {
84 let id = {
85 let mut inner = self.0.borrow_mut();
86 f(&mut inner.value);
87 inner.id
88 };
89 self.notify_and_request_frame(id);
90 }
91
92 fn notify_and_request_frame(&self, id: usize) {
93 reactive::without_observer(|| {
96 let inner = self.0.borrow();
97 let vref = &inner.value;
98 for s in &inner.subs {
99 if let Some(cb) = s.as_ref() {
100 cb(vref);
101 }
102 }
103 });
104
105 reactive::signal_changed(id);
106 crate::signal_fired();
107 crate::request_frame();
108 }
109
110 pub fn subscribe(&self, f: impl Fn(&T) + 'static) -> SubId {
111 let mut inner = self.0.borrow_mut();
112 inner.subs.push(Some(Box::new(f)));
113 inner.subs.len() - 1
114 }
115
116 pub fn unsubscribe(&self, id: SubId) -> bool {
118 let mut inner = self.0.borrow_mut();
119 if id < inner.subs.len() {
120 inner.subs[id] = None;
121 while inner.subs.last().is_some_and(|s| s.is_none()) {
123 inner.subs.pop();
124 }
125 true
126 } else {
127 false
128 }
129 }
130
131 pub fn subscribe_guard(&self, f: impl Fn(&T) + 'static) -> SubGuard<T> {
133 let id = self.subscribe(f);
134 SubGuard {
135 sig: self.clone(),
136 id,
137 }
138 }
139}
140
141pub fn signal<T>(t: T) -> Signal<T> {
142 Signal::new(t)
143}
144
145pub struct SubGuard<T: 'static> {
147 sig: crate::Signal<T>,
148 id: SubId,
149}
150impl<T> Drop for SubGuard<T> {
151 fn drop(&mut self) {
152 let _ = self.sig.unsubscribe(self.id);
153 }
154}