1use std::sync::Arc;
8
9use parking_lot::RwLock;
10use serde::{Deserialize, Serialize};
11use serde_json::Value;
12
13use super::context::current_context;
14
15#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize, Deserialize)]
17pub struct SignalId(pub u32);
18
19impl std::fmt::Display for SignalId {
20 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
21 write!(f, "s{}", self.0)
22 }
23}
24
25struct SignalInner<T> {
27 id: SignalId,
28 value: RwLock<T>,
29 subscribers: RwLock<Vec<u32>>,
33}
34
35pub struct Signal<T> {
37 inner: Arc<SignalInner<T>>,
38}
39
40impl<T> Clone for Signal<T> {
41 fn clone(&self) -> Self {
42 Self {
43 inner: self.inner.clone(),
44 }
45 }
46}
47
48impl<T> Signal<T>
49where
50 T: Clone + Serialize + 'static,
51{
52 pub fn new(initial: T) -> Self {
56 let id = current_context()
57 .map(|ctx| ctx.next_signal_id())
58 .unwrap_or_else(fallback_id);
59
60 let signal = Self {
61 inner: Arc::new(SignalInner {
62 id,
63 value: RwLock::new(initial),
64 subscribers: RwLock::new(Vec::new()),
65 }),
66 };
67
68 if let Some(ctx) = current_context() {
69 ctx.register_signal(id, signal.serialize_value());
70 }
71
72 signal
73 }
74
75 pub fn id(&self) -> SignalId {
76 self.inner.id
77 }
78
79 pub fn peek(&self) -> T {
81 self.inner.value.read().clone()
82 }
83
84 pub fn get(&self) -> T {
87 self.track();
88 self.peek()
89 }
90
91 pub fn set(&self, value: T) {
93 *self.inner.value.write() = value;
94 self.notify();
95 }
96
97 pub fn update<F>(&self, f: F)
99 where
100 F: FnOnce(&mut T),
101 {
102 let mut guard = self.inner.value.write();
103 f(&mut guard);
104 drop(guard);
105 self.notify();
106 }
107
108 fn track(&self) {
109 if let Some(ctx) = current_context() {
110 if let Some(eid) = ctx.current_effect_id() {
111 ctx.record_effect_dep(eid, self.inner.id);
112 let mut subs = self.inner.subscribers.write();
113 if !subs.contains(&eid) {
114 subs.push(eid);
115 }
116 }
117 }
118 }
119
120 fn notify(&self) {
121 if let Some(ctx) = current_context() {
122 let subs = self.inner.subscribers.read().clone();
123 for eid in subs {
124 ctx.run_effect(eid);
125 }
126 ctx.update_signal(self.inner.id, self.serialize_value());
127 }
128 }
129
130 fn serialize_value(&self) -> Value {
131 serde_json::to_value(&*self.inner.value.read()).unwrap_or(Value::Null)
132 }
133
134 pub fn split(self) -> (ReadSignal<T>, WriteSignal<T>) {
136 (
137 ReadSignal {
138 signal: self.clone(),
139 },
140 WriteSignal { signal: self },
141 )
142 }
143}
144
145#[derive(Clone)]
147pub struct ReadSignal<T> {
148 signal: Signal<T>,
149}
150
151impl<T: Clone + Serialize + 'static> ReadSignal<T> {
152 pub fn id(&self) -> SignalId {
153 self.signal.id()
154 }
155 pub fn get(&self) -> T {
156 self.signal.get()
157 }
158 pub fn peek(&self) -> T {
159 self.signal.peek()
160 }
161}
162
163#[derive(Clone)]
165pub struct WriteSignal<T> {
166 signal: Signal<T>,
167}
168
169impl<T: Clone + Serialize + 'static> WriteSignal<T> {
170 pub fn id(&self) -> SignalId {
171 self.signal.id()
172 }
173 pub fn set(&self, value: T) {
174 self.signal.set(value)
175 }
176 pub fn update<F>(&self, f: F)
177 where
178 F: FnOnce(&mut T),
179 {
180 self.signal.update(f)
181 }
182}
183
184pub fn signal<T: Clone + Serialize + 'static>(initial: T) -> Signal<T> {
189 Signal::new(initial)
190}
191
192pub fn use_signal<T: Clone + Serialize + 'static>(initial: T) -> Signal<T> {
194 signal(initial)
195}
196
197fn fallback_id() -> SignalId {
198 use std::sync::atomic::{AtomicU32, Ordering};
199 static COUNTER: AtomicU32 = AtomicU32::new(1_000_000);
200 SignalId(COUNTER.fetch_add(1, Ordering::Relaxed))
201}