1mod reactive;
11
12pub use reactive::{
13 create_computed, create_effect, create_signal, Effect, ReactiveComputed, ReactiveScope, Signal,
14 SignalError,
15};
16
17use std::{
18 any::TypeId,
19 collections::HashMap,
20 sync::{Arc, Mutex},
21};
22
23type SubscriberCallback = Box<dyn Fn() + Send + Sync>;
25type SubscriberMap = HashMap<TypeId, Vec<SubscriberCallback>>;
26type StateValue = Arc<Mutex<Box<dyn std::any::Any + Send + Sync>>>;
28type StateMap = HashMap<TypeId, StateValue>;
29
30#[derive(Clone)]
35pub struct StateContainer {
36 #[allow(clippy::type_complexity)]
39 values: Arc<Mutex<StateMap>>,
40 pub(crate) subscribers: Arc<Mutex<SubscriberMap>>,
43}
44
45impl std::fmt::Debug for StateContainer {
46 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
47 f.debug_struct("StateContainer")
48 .field("values", &"[StateMap]")
49 .field("subscribers", &"[SubscriberMap]")
50 .finish()
51 }
52}
53
54impl StateContainer {
55 pub fn new() -> Self {
57 Self {
58 values: Arc::new(Mutex::new(HashMap::new())),
59 subscribers: Arc::new(Mutex::new(HashMap::new())),
60 }
61 }
62
63 pub fn create<T: 'static + Clone + Send + Sync>(&self, initial: T) -> State<T> {
65 let type_id = TypeId::of::<T>();
66
67 self.values
69 .lock()
70 .unwrap()
71 .insert(type_id, Arc::new(Mutex::new(Box::new(initial.clone()))));
72
73 State {
74 container: self.clone(),
75 type_id,
76 _marker: std::marker::PhantomData,
77 }
78 }
79
80 pub fn computed<T, F>(&self, compute: F, dependencies: Vec<TypeId>) -> Computed<T>
82 where
83 T: 'static + Clone + Send + Sync,
84 F: Fn() -> T + Send + Sync + 'static,
85 {
86 let initial = compute();
88 let type_id = TypeId::of::<T>();
89
90 self.values
92 .lock()
93 .unwrap()
94 .insert(type_id, Arc::new(Mutex::new(Box::new(initial))));
95
96 Computed::new(self.clone(), compute, dependencies)
97 }
98
99 pub fn subscribe<T: 'static + Send + Sync, F: Fn() + Send + Sync + 'static>(
101 &self,
102 callback: F,
103 ) {
104 let type_id = TypeId::of::<T>();
105 let mut subscribers = self.subscribers.lock().unwrap();
106 subscribers
107 .entry(type_id)
108 .or_default()
109 .push(Box::new(callback));
110 }
111
112 pub fn notify(&self, type_id: TypeId) {
114 let subscribers = self.subscribers.lock().unwrap();
115
116 if let Some(callbacks) = subscribers.get(&type_id) {
117 for callback in callbacks {
118 callback();
119 }
120 }
121 }
122}
123
124impl Default for StateContainer {
125 fn default() -> Self {
126 Self::new()
127 }
128}
129
130pub struct State<T> {
132 container: StateContainer,
134
135 type_id: TypeId,
137
138 _marker: std::marker::PhantomData<T>,
140}
141
142impl<T: 'static + Clone + Send + Sync> State<T> {
143 pub fn get(&self) -> T {
145 let values = self.container.values.lock().unwrap();
146
147 values
148 .get(&self.type_id)
149 .and_then(|value| {
150 let lock = value.lock().unwrap();
151 lock.downcast_ref::<T>().cloned()
152 })
153 .unwrap()
154 }
155
156 pub fn set(&self, value: T) {
158 self.container
160 .values
161 .lock()
162 .unwrap()
163 .insert(self.type_id, Arc::new(Mutex::new(Box::new(value))));
164
165 self.container.notify(self.type_id);
167 }
168 pub fn update<F>(&self, f: F)
170 where
171 F: FnOnce(&T) -> T,
172 {
173 let values = self.container.values.lock().unwrap();
174
175 if let Some(value_container) = values.get(&self.type_id) {
176 let mut value_lock = value_container.lock().unwrap();
177
178 if let Some(old_value) = value_lock.downcast_ref::<T>() {
180 let new_value = f(old_value);
181 *value_lock = Box::new(new_value);
182
183 drop(value_lock);
185 drop(values);
186
187 self.container.notify(self.type_id);
189 }
190 }
191 }
192
193 pub fn on_change<F>(&self, callback: F)
195 where
196 F: Fn(&T) + Send + Sync + 'static,
197 {
198 let container = self.container.clone();
199 let type_id = self.type_id;
200
201 self.container.subscribe::<T, _>(move || {
202 let values = container.values.lock().unwrap();
204 if let Some(value_container) = values.get(&type_id) {
205 let value_lock = value_container.lock().unwrap();
206 if let Some(value) = value_lock.downcast_ref::<T>() {
207 callback(value);
208 }
209 }
210 });
211 }
212}
213
214pub struct Computed<T> {
216 container: StateContainer,
218
219 type_id: TypeId,
221
222 #[allow(dead_code)]
224 compute: Arc<Box<dyn Fn() -> T + Send + Sync>>,
225
226 dependencies: Vec<TypeId>,
228}
229
230impl<T: 'static + Clone + Send + Sync> Computed<T> {
231 pub fn new<F>(container: StateContainer, compute: F, dependencies: Vec<TypeId>) -> Self
233 where
234 F: Fn() -> T + Send + Sync + 'static,
235 {
236 let type_id = TypeId::of::<T>();
238
239 let compute_arc = Arc::new(Box::new(compute) as Box<dyn Fn() -> T + Send + Sync>);
241
242 let computed = Self {
244 container: container.clone(),
245 type_id,
246 compute: compute_arc.clone(),
247 dependencies,
248 };
249
250 for &dep_id in computed.dependencies.iter() {
252 let compute_fn = compute_arc.clone();
254 let container_clone = container.clone();
255 let type_id_clone = type_id;
256
257 let callback = move || {
259 let new_value = (*compute_fn)();
261 container_clone
262 .values
263 .lock()
264 .unwrap()
265 .insert(type_id_clone, Arc::new(Mutex::new(Box::new(new_value))));
266 };
267
268 let mut subscribers = container.subscribers.lock().unwrap();
270 subscribers
271 .entry(dep_id)
272 .or_default()
273 .push(Box::new(callback));
274 }
275
276 computed
277 }
278
279 pub fn get(&self) -> T {
281 let values = self.container.values.lock().unwrap();
282 values
283 .get(&self.type_id)
284 .and_then(|value| {
285 let lock = value.lock().unwrap();
286 lock.downcast_ref::<T>().cloned()
287 })
288 .unwrap()
289 }
290}