egui_charts/services/
events.rs1use crate::data::inbox::Inbox;
4use std::marker::PhantomData;
5use std::sync::Arc;
6use std::sync::atomic::{AtomicBool, Ordering};
7
8pub struct Events<T: Send + 'static> {
17 inbox: Arc<Inbox>,
18 key: u64,
19 active: Arc<AtomicBool>,
20 event: PhantomData<fn(T)>,
21}
22
23impl<T: Send + 'static> Events<T> {
24 pub fn push(&self, event: T) {
26 self.inbox
27 .push_answer(self.key, Box::new(event), &self.active);
28 }
29
30 pub fn is_active(&self) -> bool {
33 self.active.load(Ordering::Relaxed)
34 }
35}
36
37impl<T: Send + 'static> Clone for Events<T> {
38 fn clone(&self) -> Self {
39 Self {
40 inbox: Arc::clone(&self.inbox),
41 key: self.key,
42 active: Arc::clone(&self.active),
43 event: PhantomData,
44 }
45 }
46}
47
48pub(crate) struct Listener(Arc<AtomicBool>);
50
51impl Listener {
52 pub(crate) fn new<T: Send + 'static>(inbox: &Arc<Inbox>, key: u64) -> (Self, Events<T>) {
54 let active = Arc::new(AtomicBool::new(true));
55 let events = Events {
56 inbox: Arc::clone(inbox),
57 key,
58 active: Arc::clone(&active),
59 event: PhantomData,
60 };
61 (Self(active), events)
62 }
63
64 pub(crate) fn is_active(&self) -> bool {
67 self.0.load(Ordering::Relaxed)
68 }
69}
70
71impl Drop for Listener {
72 fn drop(&mut self) {
73 self.0.store(false, Ordering::Relaxed);
74 }
75}
76
77#[cfg(test)]
78mod tests {
79 use super::*;
80 use std::sync::atomic::AtomicUsize;
81
82 fn counting_wakes(inbox: &Inbox) -> Arc<AtomicUsize> {
83 let wakes = Arc::new(AtomicUsize::new(0));
84 let counter = Arc::clone(&wakes);
85 inbox.set_waker(move || {
86 counter.fetch_add(1, Ordering::Relaxed);
87 });
88 wakes
89 }
90
91 fn drain(inbox: &Inbox) -> Vec<(u64, u32)> {
93 let answers = inbox.drain().answers.into_iter();
94 answers
95 .map(|(key, event)| (key, *event.downcast::<u32>().unwrap()))
96 .collect()
97 }
98
99 #[test]
105 fn a_stream_takes_10_000_pushes_per_frame_in_order_then_lags() {
106 let inbox = Arc::new(Inbox::default());
107 let wakes = counting_wakes(&inbox);
108 let (listener, events) = Listener::new::<u32>(&inbox, 1);
109 let (_other_listener, other) = Listener::new::<u32>(&inbox, 2);
110 let producer = events.clone();
111 std::thread::spawn(move || (0..10_000).for_each(|i| producer.push(i)))
112 .join()
113 .unwrap();
114 other.push(7);
115 assert_eq!(wakes.load(Ordering::Relaxed), 1);
116 let full_frame = Vec::from_iter((0..10_000).map(|i| (1, i)));
117 assert_eq!(drain(&inbox), [full_frame.clone(), vec![(2, 7)]].concat());
118
119 (0..10_000).for_each(|i| events.push(i));
120 assert!(events.is_active() && listener.is_active());
121 assert_eq!(wakes.load(Ordering::Relaxed), 2);
122 events.push(10_000);
123 other.push(8);
124 assert!(!events.is_active() && !listener.is_active());
125 assert!(other.is_active());
126 assert_eq!(drain(&inbox), [full_frame, vec![(2, 8)]].concat());
127 }
128
129 #[test]
133 fn a_stopped_stream_is_inactive_and_ignored() {
134 let inbox = Arc::new(Inbox::default());
135 let wakes = counting_wakes(&inbox);
136 let (listener, events) = Listener::new::<u32>(&inbox, 1);
137 let producer = events.clone();
138 events.push(1);
139 drop(listener);
140 assert!(!events.is_active() && !producer.is_active());
141 assert_eq!(drain(&inbox), [(1, 1)]);
142 std::thread::spawn(move || producer.push(2)).join().unwrap();
143 assert_eq!(drain(&inbox), []);
144 assert_eq!(wakes.load(Ordering::Relaxed), 1);
145 }
146}