async_event_rs/lib.rs
1use futures::future::{FutureExt, JoinAll, LocalBoxFuture, join_all};
2use slab::Slab;
3use std::future::Future;
4
5/// Type alias for asynchronous event handlers.
6///
7/// This represents a boxed function that takes a reference to event arguments
8/// and returns a boxed local future that resolves to ().
9pub type AsyncEventHandler<'a, TEventArgs> = Box<dyn Fn(TEventArgs) -> LocalBoxFuture<'a, ()> + 'a>;
10
11/// An asynchronous event that can have multiple handlers attached to it.
12///
13/// This is similar to C#'s `event` keyword but designed for async/await patterns.
14/// Handlers are stored in a slab storage for efficient access by index.
15///
16/// # Examples
17///
18/// ```
19/// use async_event_rs::AsyncEvent;
20///
21/// #[derive(Debug, Copy, Clone, Eq, PartialEq)]
22/// struct EventArgs<'a> {
23/// id: u32,
24/// message: &'a str,
25/// }
26///
27/// # futures::executor::block_on(async {
28/// let mut event = AsyncEvent::<EventArgs>::new();
29/// event.add(|args| async move {
30/// println!("Event triggered with args: {:?}", args);
31/// assert_eq!(args, EventArgs {id: 0, message: ""});
32/// });
33///
34/// let arg = EventArgs {id: 0, message: ""};
35/// event.invoke_async(arg).await;
36/// # });
37/// ```
38pub struct AsyncEvent<'a, TEventArgs> {
39 handlers: Slab<AsyncEventHandler<'a, TEventArgs>>,
40}
41
42impl<'a, TEventArgs> Default for AsyncEvent<'a, TEventArgs> {
43 fn default() -> Self {
44 Self::new()
45 }
46}
47
48impl<'a, TEventArgs> AsyncEvent<'a, TEventArgs> {
49 /// Creates a new, empty AsyncEvent
50 ///
51 /// # Examples
52 ///
53 /// ```
54 /// use async_event_rs::AsyncEvent;
55 ///
56 /// # futures::executor::block_on(async {
57 /// let mut event: AsyncEvent<(i32, &str)> = AsyncEvent::new();
58 /// event.add(|args| async move {
59 /// println!("Event triggered with args: {:?}", args);
60 /// assert_eq!(args, (0, ""));
61 /// });
62 ///
63 /// event.invoke_async((0, "")).await;
64 /// # });
65 /// ```
66 pub fn new() -> Self {
67 Self {
68 handlers: Slab::new(),
69 }
70 }
71
72 /// Adds an event handler to the event.
73 ///
74 /// The handler should be a closure that accepts a reference to the event arguments
75 /// and returns a future. The future will be executed when the event is triggered.
76 ///
77 /// Returns a handle that can be used to remove the handler later.
78 ///
79 /// # Examples
80 ///
81 /// ```
82 /// use async_event_rs::AsyncEvent;
83 ///
84 /// # futures::executor::block_on(async {
85 /// let mut event = AsyncEvent::<()>::new();
86 /// let handle = event.add(|args| async move {
87 /// println!("Event triggered");
88 /// });
89 /// # });
90 /// ```
91 pub fn add<F, Fut>(&mut self, handler: F) -> usize
92 where
93 F: Fn(TEventArgs) -> Fut + 'a,
94 Fut: Future<Output = ()> + 'a,
95 {
96 self.handlers
97 .insert(Box::new(move |arg| handler(arg).boxed_local()))
98 }
99
100 /// Removes an event handler using its handle.
101 ///
102 /// Returns `true` if the handler was found and removed, `false` otherwise.
103 ///
104 /// # Examples
105 ///
106 /// ```
107 /// use async_event_rs::AsyncEvent;
108 ///
109 /// # futures::executor::block_on(async {
110 /// let mut event = AsyncEvent::<()>::new();
111 /// let handle = event.add(|args| async move {
112 /// println!("Event triggered");
113 /// });
114 ///
115 /// assert!(event.remove(handle));
116 /// assert!(!event.remove(handle)); // Already removed
117 /// # });
118 /// ```
119 pub fn remove(&mut self, handle: usize) -> bool {
120 self.handlers.try_remove(handle).is_some()
121 }
122
123 /// Removes all event handlers.
124 ///
125 /// # Examples
126 ///
127 /// ```
128 /// use async_event_rs::AsyncEvent;
129 ///
130 /// # futures::executor::block_on(async {
131 /// let mut event = AsyncEvent::<()>::new();
132 /// event.add(|args| async move { println!("Handler 1"); });
133 /// event.add(|args| async move { println!("Handler 2"); });
134 ///
135 /// event.clear(); // Remove all handlers
136 /// # });
137 /// ```
138 pub fn clear(&mut self) {
139 self.handlers.clear();
140 }
141
142 /// Invokes all event handlers sequentially (one after another).
143 ///
144 /// Each handler is awaited before the next one is executed.
145 ///
146 /// # Examples
147 ///
148 /// ```
149 /// use async_event_rs::AsyncEvent;
150 ///
151 /// # futures::executor::block_on(async {
152 /// let mut event = AsyncEvent::new();
153 /// event.add(|args| async move { println!("Handler 1"); });
154 /// event.add(|args| async move { println!("Handler 2"); });
155 ///
156 /// event.invoke_async(()).await; // Execute all handlers in order
157 /// # });
158 /// ```
159 pub async fn invoke_async(&self, arg: TEventArgs)
160 where
161 TEventArgs: Clone,
162 {
163 for (_, handler) in self.handlers.iter() {
164 handler(arg.clone()).await;
165 }
166 }
167
168 /// Invokes all event handlers in parallel.
169 ///
170 /// All handlers are spawned concurrently and executed simultaneously.
171 ///
172 /// # Examples
173 ///
174 /// ```
175 /// use async_event_rs::AsyncEvent;
176 ///
177 /// # futures::executor::block_on(async {
178 /// let mut event = AsyncEvent::new();
179 /// event.add(|args| async move { println!("Handler 1"); });
180 /// event.add(|args| async move { println!("Handler 2"); });
181 ///
182 /// event.invoke_parallel_async(()).await; // Execute all handlers in parallel
183 /// # });
184 /// ```
185 pub fn invoke_parallel_async(&self, arg: TEventArgs) -> JoinAll<impl Future<Output = ()> + 'a>
186 where
187 TEventArgs: Clone,
188 {
189 join_all(
190 self.handlers
191 .iter()
192 .map(|(_, handler)| handler(arg.clone())),
193 )
194 }
195}
196
197#[cfg(test)]
198mod tests {
199 use super::*;
200 use std::cell::RefCell;
201 use std::rc::Rc;
202
203 #[tokio::test]
204 async fn test_invoke_async() {
205 let counter = Rc::new(RefCell::new(0));
206 let mut event = AsyncEvent::new();
207
208 event.invoke_async(()).await;
209
210 event.add(|_| {
211 let counter = Rc::clone(&counter);
212 async move {
213 *counter.borrow_mut() += 1;
214 }
215 });
216
217 event.add(|_| {
218 let counter = Rc::clone(&counter);
219 async move {
220 *counter.borrow_mut() += 1;
221 }
222 });
223
224 event.invoke_async(()).await;
225 assert_eq!(*counter.borrow(), 2);
226 }
227
228 #[tokio::test]
229 async fn test_invoke_parallel_async() {
230 let log = Rc::new(RefCell::new(vec![]));
231 let mut event = AsyncEvent::new();
232
233 event.invoke_parallel_async(()).await;
234
235 for i in 0..3 {
236 let log = Rc::clone(&log);
237 event.add(move |_| {
238 let log = Rc::clone(&log);
239 async move {
240 log.borrow_mut().push(i);
241 }
242 });
243 }
244
245 event.invoke_parallel_async(()).await;
246
247 let result = log.borrow().clone();
248 assert_eq!(result.len(), 3);
249 for i in 0..3 {
250 assert!(result.contains(&i));
251 }
252 }
253
254 #[tokio::test]
255 async fn test_remove_handler() {
256 let counter = Rc::new(RefCell::new(0));
257 let mut event = AsyncEvent::new();
258
259 let handle = event.add(|_| {
260 let counter = Rc::clone(&counter);
261 async move {
262 *counter.borrow_mut() += 1;
263 }
264 });
265
266 assert!(event.remove(handle));
267 event.invoke_async(()).await;
268
269 assert_eq!(*counter.borrow(), 0);
270 }
271
272 #[tokio::test]
273 async fn test_clear_handlers() {
274 let counter = Rc::new(RefCell::new(0));
275 let mut event = AsyncEvent::new();
276
277 for _ in 0..5 {
278 event.add(|_| {
279 let counter = Rc::clone(&counter);
280 async move {
281 *counter.borrow_mut() += 1;
282 }
283 });
284 }
285
286 event.clear();
287 event.invoke_async(()).await;
288
289 assert_eq!(*counter.borrow(), 0);
290 }
291
292 #[tokio::test]
293 async fn test_add_handler_twice() {
294 let counter = Rc::new(RefCell::new(0));
295 let mut event = AsyncEvent::new();
296
297 let handler = |_| {
298 let counter: Rc<RefCell<i32>> = Rc::clone(&counter);
299 async move {
300 *counter.borrow_mut() += 1;
301 }
302 };
303
304 event.add(handler);
305 event.add(handler);
306
307 event.invoke_async(()).await;
308 assert_eq!(*counter.borrow(), 2);
309 }
310
311 #[tokio::test]
312 async fn test_remove_handler_twice() {
313 let counter = Rc::new(RefCell::new(0));
314 let mut event = AsyncEvent::new();
315
316 let handle = event.add(|_| {
317 let counter: Rc<RefCell<i32>> = Rc::clone(&counter);
318 async move {
319 *counter.borrow_mut() += 1;
320 }
321 });
322
323 assert!(event.remove(handle));
324 assert!(!event.remove(handle));
325
326 event.invoke_async(()).await;
327 assert_eq!(*counter.borrow(), 0);
328 }
329}