1use crate::geometric::{FromGeometric, IntoGeometric, GA3};
11use std::cell::RefCell;
12use std::rc::Rc;
13
14#[derive(Debug, Clone)]
16pub struct Occurrence<T> {
17 pub value: T,
19 pub timestamp: f64,
21}
22
23#[allow(clippy::type_complexity)]
43pub struct Event<T> {
44 subscribers: Rc<RefCell<Vec<(usize, Box<dyn Fn(&Occurrence<T>)>)>>>,
46
47 next_id: Rc<RefCell<usize>>,
49
50 start_time: std::time::Instant,
52
53 transform: Option<GA3>,
55}
56
57impl<T> Clone for Event<T> {
58 fn clone(&self) -> Self {
59 Self {
60 subscribers: Rc::clone(&self.subscribers),
61 next_id: Rc::clone(&self.next_id),
62 start_time: self.start_time,
63 transform: self.transform.clone(),
64 }
65 }
66}
67
68impl<T: Clone + 'static> Event<T> {
69 pub fn new() -> Self {
71 Self {
72 subscribers: Rc::new(RefCell::new(Vec::new())),
73 next_id: Rc::new(RefCell::new(0)),
74 start_time: std::time::Instant::now(),
75 transform: None,
76 }
77 }
78
79 pub fn emit(&self, value: T) {
81 let occurrence = Occurrence {
82 value,
83 timestamp: self.start_time.elapsed().as_secs_f64(),
84 };
85
86 for (_, callback) in self.subscribers.borrow().iter() {
87 callback(&occurrence);
88 }
89 }
90
91 pub fn subscribe<F>(&self, callback: F) -> EventSubscription
93 where
94 F: Fn(&T) + 'static,
95 {
96 let id = {
97 let mut next = self.next_id.borrow_mut();
98 let id = *next;
99 *next += 1;
100 id
101 };
102
103 self.subscribers
104 .borrow_mut()
105 .push((id, Box::new(move |occ| callback(&occ.value))));
106
107 let subscribers = Rc::clone(&self.subscribers);
108 EventSubscription {
109 id,
110 unsubscribe: Rc::new(RefCell::new(Some(Box::new(move || {
111 subscribers.borrow_mut().retain(|(i, _)| *i != id);
112 })))),
113 }
114 }
115
116 pub fn map<U, F>(&self, f: F) -> Event<U>
118 where
119 U: Clone + 'static,
120 F: Fn(T) -> U + 'static,
121 {
122 let mapped = Event::<U>::new();
123
124 let mapped_clone = mapped.clone();
125 self.subscribe(move |value| {
126 mapped_clone.emit(f(value.clone()));
127 });
128
129 mapped
130 }
131
132 pub fn filter<F>(&self, predicate: F) -> Event<T>
134 where
135 F: Fn(&T) -> bool + 'static,
136 {
137 let filtered = Event::<T>::new();
138
139 let filtered_clone = filtered.clone();
140 self.subscribe(move |value| {
141 if predicate(value) {
142 filtered_clone.emit(value.clone());
143 }
144 });
145
146 filtered
147 }
148
149 pub fn merge(&self, other: &Event<T>) -> Event<T> {
151 let merged = Event::<T>::new();
152
153 let merged_clone = merged.clone();
154 self.subscribe(move |value| {
155 merged_clone.emit(value.clone());
156 });
157
158 let merged_clone = merged.clone();
159 other.subscribe(move |value| {
160 merged_clone.emit(value.clone());
161 });
162
163 merged
164 }
165
166 pub fn fold<S, F>(&self, initial: S, f: F) -> crate::Behavior<S>
168 where
169 S: IntoGeometric + FromGeometric + Clone + 'static,
170 F: Fn(S, T) -> S + 'static,
171 {
172 let behavior = crate::behavior(initial);
173
174 let behavior_clone = behavior.clone();
175 self.subscribe(move |value| {
176 behavior_clone.update(|state| f(state, value.clone()));
177 });
178
179 behavior
180 }
181}
182
183impl<T: Clone + 'static> Default for Event<T> {
184 fn default() -> Self {
185 Self::new()
186 }
187}
188
189#[allow(clippy::type_complexity)]
191pub struct EventSubscription {
192 #[allow(dead_code)] id: usize,
194 unsubscribe: Rc<RefCell<Option<Box<dyn Fn()>>>>,
195}
196
197impl EventSubscription {
198 pub fn unsubscribe(self) {
200 if let Some(unsub) = self.unsubscribe.borrow_mut().take() {
201 unsub();
202 }
203 }
204}
205
206pub fn event<T: Clone + 'static>() -> Event<T> {
218 Event::new()
219}
220
221#[cfg(test)]
222mod tests {
223 use super::*;
224 use std::cell::Cell;
225
226 #[test]
227 fn test_event_new_and_emit() {
228 let evt = event::<i32>();
229 let received = Rc::new(Cell::new(0));
230 let received_clone = Rc::clone(&received);
231
232 evt.subscribe(move |value| {
233 received_clone.set(*value);
234 });
235
236 evt.emit(42);
237 assert_eq!(received.get(), 42);
238 }
239
240 #[test]
241 fn test_event_multiple_subscribers() {
242 let evt = event::<i32>();
243 let count = Rc::new(Cell::new(0));
244
245 let count1 = Rc::clone(&count);
246 evt.subscribe(move |_| count1.set(count1.get() + 1));
247
248 let count2 = Rc::clone(&count);
249 evt.subscribe(move |_| count2.set(count2.get() + 1));
250
251 evt.emit(1);
252 assert_eq!(count.get(), 2);
253 }
254
255 #[test]
256 fn test_event_unsubscribe() {
257 let evt = event::<i32>();
258 let count = Rc::new(Cell::new(0));
259 let count_clone = Rc::clone(&count);
260
261 let sub = evt.subscribe(move |_| {
262 count_clone.set(count_clone.get() + 1);
263 });
264
265 evt.emit(1);
266 assert_eq!(count.get(), 1);
267
268 sub.unsubscribe();
269
270 evt.emit(2);
271 assert_eq!(count.get(), 1); }
273
274 #[test]
275 fn test_event_map() {
276 let evt = event::<i32>();
277 let doubled = evt.map(|n| n * 2);
278
279 let received = Rc::new(Cell::new(0));
280 let received_clone = Rc::clone(&received);
281
282 doubled.subscribe(move |value| {
283 received_clone.set(*value);
284 });
285
286 evt.emit(5);
287 assert_eq!(received.get(), 10);
288 }
289
290 #[test]
291 fn test_event_filter() {
292 let evt = event::<i32>();
293 let evens = evt.filter(|n| n % 2 == 0);
294
295 let received = Rc::new(RefCell::new(Vec::new()));
296 let received_clone = Rc::clone(&received);
297
298 evens.subscribe(move |value| {
299 received_clone.borrow_mut().push(*value);
300 });
301
302 evt.emit(1);
303 evt.emit(2);
304 evt.emit(3);
305 evt.emit(4);
306
307 assert_eq!(*received.borrow(), vec![2, 4]);
308 }
309
310 #[test]
311 fn test_event_merge() {
312 let evt1 = event::<i32>();
313 let evt2 = event::<i32>();
314 let merged = evt1.merge(&evt2);
315
316 let received = Rc::new(RefCell::new(Vec::new()));
317 let received_clone = Rc::clone(&received);
318
319 merged.subscribe(move |value| {
320 received_clone.borrow_mut().push(*value);
321 });
322
323 evt1.emit(1);
324 evt2.emit(2);
325 evt1.emit(3);
326
327 assert_eq!(*received.borrow(), vec![1, 2, 3]);
328 }
329
330 #[test]
331 fn test_event_fold() {
332 let clicks = event::<()>();
333 let count = clicks.fold(0i32, |n, _| n + 1);
334
335 assert_eq!(count.sample(), 0);
336
337 clicks.emit(());
338 assert_eq!(count.sample(), 1);
339
340 clicks.emit(());
341 clicks.emit(());
342 assert_eq!(count.sample(), 3);
343 }
344}