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 invoked 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 /// let mut event: AsyncEvent<()> = AsyncEvent::new();
57 /// ```
58 pub fn new() -> Self {
59 Self {
60 handlers: Slab::new(),
61 }
62 }
63
64 /// Adds an event handler to the event.
65 ///
66 /// The handler should be a closure that accepts a reference to the event arguments
67 /// and returns a future. The future will be executed when the event is invoked.
68 ///
69 /// Returns a handle that can be used to remove the handler later.
70 ///
71 /// # Examples
72 ///
73 /// ```
74 /// use async_event_rs::AsyncEvent;
75 ///
76 /// # futures::executor::block_on(async {
77 /// let mut event = AsyncEvent::<()>::new();
78 /// let handle = event.add(|args| async move {
79 /// println!("Event invoked");
80 /// });
81 /// # });
82 /// ```
83 pub fn add<F, Fut>(&mut self, handler: F) -> usize
84 where
85 F: Fn(TEventArgs) -> Fut + 'a,
86 Fut: Future<Output = ()> + 'a,
87 {
88 self.handlers
89 .insert(Box::new(move |arg| handler(arg).boxed_local()))
90 }
91
92 /// Removes an event handler using its handle.
93 ///
94 /// Returns `true` if the handler was found and removed, `false` otherwise.
95 ///
96 /// # Examples
97 ///
98 /// ```
99 /// use async_event_rs::AsyncEvent;
100 ///
101 /// # futures::executor::block_on(async {
102 /// let mut event = AsyncEvent::<()>::new();
103 /// let handle = event.add(|args| async move {
104 /// println!("Event invoked");
105 /// });
106 ///
107 /// assert!(event.remove(handle));
108 /// assert!(!event.remove(handle)); // Already removed
109 /// # });
110 /// ```
111 pub fn remove(&mut self, handle: usize) -> bool {
112 self.handlers.try_remove(handle).is_some()
113 }
114
115 /// Removes all event handlers.
116 ///
117 /// # Examples
118 ///
119 /// ```
120 /// use async_event_rs::AsyncEvent;
121 ///
122 /// # futures::executor::block_on(async {
123 /// let mut event = AsyncEvent::<()>::new();
124 /// event.add(|args| async move { println!("Handler 1"); });
125 /// event.add(|args| async move { println!("Handler 2"); });
126 ///
127 /// event.clear(); // Remove all handlers
128 /// # });
129 /// ```
130 pub fn clear(&mut self) {
131 self.handlers.clear();
132 }
133
134 /// Invokes all event handlers sequentially (one after another).
135 ///
136 /// Each handler is awaited before the next one is executed.
137 ///
138 /// # Examples
139 ///
140 /// ```
141 /// use async_event_rs::AsyncEvent;
142 ///
143 /// # futures::executor::block_on(async {
144 /// let mut event = AsyncEvent::new();
145 /// event.add(|args| async move { println!("Handler 1"); });
146 /// event.add(|args| async move { println!("Handler 2"); });
147 ///
148 /// event.invoke_async(()).await; // Execute all handlers in order
149 /// # });
150 /// ```
151 pub async fn invoke_async(&self, arg: TEventArgs)
152 where
153 TEventArgs: Clone,
154 {
155 for (_, handler) in self.handlers.iter() {
156 handler(arg.clone()).await;
157 }
158 }
159
160 /// Invokes all event handlers in parallel.
161 ///
162 /// All handlers are spawned concurrently and executed simultaneously.
163 ///
164 /// # Examples
165 ///
166 /// ```
167 /// use async_event_rs::AsyncEvent;
168 ///
169 /// # futures::executor::block_on(async {
170 /// let mut event = AsyncEvent::new();
171 /// event.add(|args| async move { println!("Handler 1"); });
172 /// event.add(|args| async move { println!("Handler 2"); });
173 ///
174 /// event.invoke_parallel_async(()).await; // Execute all handlers in parallel
175 /// # });
176 /// ```
177 pub fn invoke_parallel_async(&self, arg: TEventArgs) -> JoinAll<impl Future<Output = ()> + 'a>
178 where
179 TEventArgs: Clone,
180 {
181 join_all(
182 self.handlers
183 .iter()
184 .map(|(_, handler)| handler(arg.clone())),
185 )
186 }
187}
188
189#[cfg(test)]
190mod tests {
191 use super::*;
192 use std::cell::RefCell;
193 use std::rc::Rc;
194
195 #[tokio::test]
196 async fn test_invoke_async() {
197 let counter = Rc::new(RefCell::new(0));
198 let mut event = AsyncEvent::new();
199
200 event.invoke_async(()).await;
201
202 event.add(|_| {
203 let counter = Rc::clone(&counter);
204 async move {
205 *counter.borrow_mut() += 1;
206 }
207 });
208
209 event.add(|_| {
210 let counter = Rc::clone(&counter);
211 async move {
212 *counter.borrow_mut() += 1;
213 }
214 });
215
216 event.invoke_async(()).await;
217 event.invoke_async(()).await;
218 assert_eq!(*counter.borrow(), 4);
219 }
220
221 #[tokio::test]
222 async fn test_invoke_parallel_async() {
223 let log = Rc::new(RefCell::new(vec![]));
224 let mut event = AsyncEvent::new();
225
226 event.invoke_parallel_async(()).await;
227
228 for i in 0..3 {
229 let log = Rc::clone(&log);
230 event.add(move |_| {
231 let log = Rc::clone(&log);
232 async move {
233 log.borrow_mut().push(i);
234 }
235 });
236 }
237
238 event.invoke_parallel_async(()).await;
239
240 let result = log.borrow().clone();
241 assert_eq!(result.len(), 3);
242 for i in 0..3 {
243 assert!(result.contains(&i));
244 }
245 }
246
247 #[tokio::test]
248 async fn test_remove_handler() {
249 let counter = Rc::new(RefCell::new(0));
250 let mut event = AsyncEvent::new();
251
252 let handle = event.add(|_| {
253 let counter = Rc::clone(&counter);
254 async move {
255 *counter.borrow_mut() += 1;
256 }
257 });
258
259 assert!(event.remove(handle));
260 event.invoke_async(()).await;
261
262 assert_eq!(*counter.borrow(), 0);
263 }
264
265 #[tokio::test]
266 async fn test_clear_handlers() {
267 let counter = Rc::new(RefCell::new(0));
268 let mut event = AsyncEvent::new();
269
270 for _ in 0..5 {
271 event.add(|_| {
272 let counter = Rc::clone(&counter);
273 async move {
274 *counter.borrow_mut() += 1;
275 }
276 });
277 }
278
279 event.clear();
280 event.invoke_async(()).await;
281
282 assert_eq!(*counter.borrow(), 0);
283 }
284
285 #[tokio::test]
286 async fn test_add_handler_twice() {
287 let counter = Rc::new(RefCell::new(0));
288 let mut event = AsyncEvent::new();
289
290 let handler = |_| {
291 let counter: Rc<RefCell<i32>> = Rc::clone(&counter);
292 async move {
293 *counter.borrow_mut() += 1;
294 }
295 };
296
297 event.add(handler);
298 event.add(handler);
299
300 event.invoke_async(()).await;
301 assert_eq!(*counter.borrow(), 2);
302 }
303
304 #[tokio::test]
305 async fn test_remove_handler_twice() {
306 let counter = Rc::new(RefCell::new(0));
307 let mut event = AsyncEvent::new();
308
309 let handle = event.add(|_| {
310 let counter: Rc<RefCell<i32>> = Rc::clone(&counter);
311 async move {
312 *counter.borrow_mut() += 1;
313 }
314 });
315
316 assert!(event.remove(handle));
317 assert!(!event.remove(handle));
318
319 event.invoke_async(()).await;
320 assert_eq!(*counter.borrow(), 0);
321 }
322}