rustial_engine/
event_emitter.rs1use crate::interaction::{InteractionEvent, InteractionEventKind};
17
18#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
22pub struct ListenerId(u64);
23
24struct Listener {
26 id: ListenerId,
27 kind: InteractionEventKind,
28 callback: Box<dyn Fn(&InteractionEvent) + Send + Sync>,
29 once: bool,
30}
31
32pub struct EventEmitter {
38 listeners: Vec<Listener>,
39 next_id: u64,
40}
41
42impl Default for EventEmitter {
43 fn default() -> Self {
44 Self::new()
45 }
46}
47
48impl EventEmitter {
49 pub fn new() -> Self {
51 Self {
52 listeners: Vec::new(),
53 next_id: 0,
54 }
55 }
56
57 pub fn on<F>(&mut self, kind: InteractionEventKind, callback: F) -> ListenerId
61 where
62 F: Fn(&InteractionEvent) + Send + Sync + 'static,
63 {
64 let id = self.alloc_id();
65 self.listeners.push(Listener {
66 id,
67 kind,
68 callback: Box::new(callback),
69 once: false,
70 });
71 id
72 }
73
74 pub fn once<F>(&mut self, kind: InteractionEventKind, callback: F) -> ListenerId
78 where
79 F: Fn(&InteractionEvent) + Send + Sync + 'static,
80 {
81 let id = self.alloc_id();
82 self.listeners.push(Listener {
83 id,
84 kind,
85 callback: Box::new(callback),
86 once: true,
87 });
88 id
89 }
90
91 pub fn off(&mut self, id: ListenerId) -> bool {
95 let before = self.listeners.len();
96 self.listeners.retain(|l| l.id != id);
97 self.listeners.len() < before
98 }
99
100 pub fn dispatch(&mut self, events: &[InteractionEvent]) {
104 if self.listeners.is_empty() || events.is_empty() {
105 return;
106 }
107
108 let mut to_remove: Vec<ListenerId> = Vec::new();
109
110 for event in events {
111 for listener in &self.listeners {
112 if listener.kind == event.kind {
113 (listener.callback)(event);
114 if listener.once {
115 to_remove.push(listener.id);
116 }
117 }
118 }
119 }
120
121 if !to_remove.is_empty() {
122 self.listeners.retain(|l| !to_remove.contains(&l.id));
123 }
124 }
125
126 pub fn listener_count(&self) -> usize {
128 self.listeners.len()
129 }
130
131 pub fn listener_count_for(&self, kind: InteractionEventKind) -> usize {
133 self.listeners.iter().filter(|l| l.kind == kind).count()
134 }
135
136 fn alloc_id(&mut self) -> ListenerId {
137 let id = ListenerId(self.next_id);
138 self.next_id += 1;
139 id
140 }
141}
142
143unsafe impl Send for EventEmitter {}
146unsafe impl Sync for EventEmitter {}
147
148#[cfg(test)]
153mod tests {
154 use super::*;
155 use crate::interaction::{InteractionEvent, InteractionEventKind, PointerKind, ScreenPoint};
156 use std::sync::atomic::{AtomicU32, Ordering};
157 use std::sync::Arc;
158
159 fn make_event(kind: InteractionEventKind) -> InteractionEvent {
160 InteractionEvent::new(kind, PointerKind::Mouse, ScreenPoint::new(0.0, 0.0))
161 }
162
163 #[test]
164 fn on_dispatches_repeatedly() {
165 let mut emitter = EventEmitter::new();
166 let counter = Arc::new(AtomicU32::new(0));
167 let c = counter.clone();
168 emitter.on(InteractionEventKind::Click, move |_| {
169 c.fetch_add(1, Ordering::Relaxed);
170 });
171
172 let events = vec![make_event(InteractionEventKind::Click)];
173 emitter.dispatch(&events);
174 emitter.dispatch(&events);
175
176 assert_eq!(counter.load(Ordering::Relaxed), 2);
177 }
178
179 #[test]
180 fn once_dispatches_only_once() {
181 let mut emitter = EventEmitter::new();
182 let counter = Arc::new(AtomicU32::new(0));
183 let c = counter.clone();
184 emitter.once(InteractionEventKind::Click, move |_| {
185 c.fetch_add(1, Ordering::Relaxed);
186 });
187
188 let events = vec![make_event(InteractionEventKind::Click)];
189 emitter.dispatch(&events);
190 emitter.dispatch(&events);
191
192 assert_eq!(counter.load(Ordering::Relaxed), 1);
193 assert_eq!(emitter.listener_count(), 0);
194 }
195
196 #[test]
197 fn off_removes_listener() {
198 let mut emitter = EventEmitter::new();
199 let counter = Arc::new(AtomicU32::new(0));
200 let c = counter.clone();
201 let id = emitter.on(InteractionEventKind::Click, move |_| {
202 c.fetch_add(1, Ordering::Relaxed);
203 });
204
205 let events = vec![make_event(InteractionEventKind::Click)];
206 emitter.dispatch(&events);
207 assert!(emitter.off(id));
208 emitter.dispatch(&events);
209
210 assert_eq!(counter.load(Ordering::Relaxed), 1);
211 }
212
213 #[test]
214 fn different_kinds_are_isolated() {
215 let mut emitter = EventEmitter::new();
216 let click_count = Arc::new(AtomicU32::new(0));
217 let move_count = Arc::new(AtomicU32::new(0));
218
219 let cc = click_count.clone();
220 emitter.on(InteractionEventKind::Click, move |_| {
221 cc.fetch_add(1, Ordering::Relaxed);
222 });
223
224 let mc = move_count.clone();
225 emitter.on(InteractionEventKind::MouseMove, move |_| {
226 mc.fetch_add(1, Ordering::Relaxed);
227 });
228
229 emitter.dispatch(&[make_event(InteractionEventKind::Click)]);
230
231 assert_eq!(click_count.load(Ordering::Relaxed), 1);
232 assert_eq!(move_count.load(Ordering::Relaxed), 0);
233 }
234
235 #[test]
236 fn listener_count_for_kind() {
237 let mut emitter = EventEmitter::new();
238 emitter.on(InteractionEventKind::Click, |_| {});
239 emitter.on(InteractionEventKind::Click, |_| {});
240 emitter.on(InteractionEventKind::MouseMove, |_| {});
241
242 assert_eq!(emitter.listener_count(), 3);
243 assert_eq!(emitter.listener_count_for(InteractionEventKind::Click), 2);
244 assert_eq!(
245 emitter.listener_count_for(InteractionEventKind::MouseMove),
246 1
247 );
248 }
249}