1use std::{
2 collections::HashMap,
3 future::Future,
4 sync::{
5 atomic::{AtomicUsize, Ordering},
6 Arc, Weak,
7 },
8};
9
10use parking_lot::Mutex;
11
12use crate::async_runtime::{global_executor, Executor, Task};
13
14use super::{select, CondWait, Either};
15
16pub type TaskID = usize;
18
19pub struct TaskGroup {
40 inner: Arc<Inner>,
41}
42
43struct Inner {
47 tasks: Mutex<HashMap<TaskID, TaskHandler>>,
48 next_id: AtomicUsize,
49 executor: Executor,
50}
51
52impl Inner {
53 fn remove(&self, id: TaskID) -> Option<TaskHandler> {
55 self.tasks.lock().remove(&id)
56 }
57}
58
59impl TaskGroup {
60 pub fn new() -> Self {
64 Self::with_inner(global_executor())
65 }
66
67 pub fn with_executor(executor: Executor) -> Self {
69 Self::with_inner(executor)
70 }
71
72 fn with_inner(executor: Executor) -> Self {
73 Self {
74 inner: Arc::new(Inner {
75 tasks: Mutex::new(HashMap::new()),
76 next_id: AtomicUsize::new(0),
77 executor,
78 }),
79 }
80 }
81
82 pub fn spawn<T, Fut>(&self, fut: Fut) -> TaskID
87 where
88 T: Send + Sync + 'static,
89 Fut: Future<Output = T> + Send + 'static,
90 {
91 self.spawn_then(fut, |_| async {})
92 }
93
94 pub fn spawn_then<T, Fut, CallbackF, CallbackFut>(
100 &self,
101 fut: Fut,
102 callback: CallbackF,
103 ) -> TaskID
104 where
105 T: Send + Sync + 'static,
106 Fut: Future<Output = T> + Send + 'static,
107 CallbackF: FnOnce(TaskResult<T>) -> CallbackFut + Send + 'static,
108 CallbackFut: Future<Output = ()> + Send + 'static,
109 {
110 let id = self.inner.next_id.fetch_add(1, Ordering::Relaxed);
111 let mut tasks = self.inner.tasks.lock();
114 let task = TaskHandler::new(
115 self.inner.executor.clone(),
116 fut,
117 callback,
118 Arc::downgrade(&self.inner),
119 id,
120 );
121 tasks.insert(id, task);
122 id
123 }
124
125 pub fn remove(&self, id: TaskID) -> Option<TaskHandler> {
128 self.inner.remove(id)
129 }
130
131 pub fn is_empty(&self) -> bool {
133 self.inner.tasks.lock().is_empty()
134 }
135
136 pub fn len(&self) -> usize {
138 self.inner.tasks.lock().len()
139 }
140
141 pub async fn cancel(&self) {
143 let handlers: Vec<TaskHandler> = self.inner.tasks.lock().drain().map(|(_, h)| h).collect();
145 for handler in handlers {
146 handler.cancel().await;
147 }
148 }
149}
150
151impl Default for TaskGroup {
152 fn default() -> Self {
153 Self::new()
154 }
155}
156
157#[derive(Debug)]
159pub enum TaskResult<T> {
160 Completed(T),
161 Cancelled,
162}
163
164impl<T: std::fmt::Debug> std::fmt::Display for TaskResult<T> {
165 fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
166 match self {
167 TaskResult::Cancelled => write!(f, "Task cancelled"),
168 TaskResult::Completed(res) => write!(f, "Task completed: {res:?}"),
169 }
170 }
171}
172
173pub struct TaskHandler {
175 task: Task<()>,
176 stop_signal: Arc<CondWait>,
179 cancel_flag: Arc<CondWait>,
181}
182
183impl TaskHandler {
184 fn new<T, Fut, CallbackF, CallbackFut>(
186 ex: Executor,
187 fut: Fut,
188 callback: CallbackF,
189 group: Weak<Inner>,
190 id: TaskID,
191 ) -> TaskHandler
192 where
193 T: Send + Sync + 'static,
194 Fut: Future<Output = T> + Send + 'static,
195 CallbackF: FnOnce(TaskResult<T>) -> CallbackFut + Send + 'static,
196 CallbackFut: Future<Output = ()> + Send + 'static,
197 {
198 let stop_signal = Arc::new(CondWait::new());
199 let stop_signal_c = stop_signal.clone();
200 let cancel_flag = Arc::new(CondWait::new());
201 let cancel_flag_c = cancel_flag.clone();
202 let task = ex.spawn(async move {
203 let result = select(stop_signal_c.wait(), fut).await;
205
206 let result = match result {
207 Either::Left(_) => TaskResult::Cancelled,
208 Either::Right(res) => TaskResult::Completed(res),
209 };
210
211 callback(result).await;
213
214 cancel_flag_c.signal().await;
215
216 if let Some(group) = group.upgrade() {
220 if let Some(handler) = group.remove(id) {
221 handler.detach();
222 }
223 }
224 });
225
226 TaskHandler {
227 task,
228 stop_signal,
229 cancel_flag,
230 }
231 }
232
233 fn detach(self) {
235 self.task.detach();
236 }
237
238 async fn cancel(self) {
241 self.stop_signal.signal().await;
242 self.cancel_flag.wait().await;
243 self.task.cancel().await;
244 }
245}
246
247#[cfg(test)]
248mod tests {
249 use std::{future, sync::Arc};
250
251 use crate::async_runtime::block_on;
252 use crate::async_util::sleep;
253
254 use super::*;
255
256 #[cfg(feature = "tokio")]
257 #[test]
258 fn test_task_group_with_tokio_executor() {
259 let ex = Arc::new(tokio::runtime::Runtime::new().unwrap());
260 ex.clone().block_on(async move {
261 let group = Arc::new(TaskGroup::with_executor(ex.into()));
262
263 group.spawn_then(future::ready(0), |res| async move {
264 assert!(matches!(res, TaskResult::Completed(0)));
265 });
266
267 group.spawn_then(future::pending::<()>(), |res| async move {
268 assert!(matches!(res, TaskResult::Cancelled));
269 });
270
271 let groupc = group.clone();
272 group.spawn_then(
273 async move {
274 groupc.spawn_then(future::pending::<()>(), |res| async move {
275 assert!(matches!(res, TaskResult::Cancelled));
276 });
277 },
278 |res| async move {
279 assert!(matches!(res, TaskResult::Completed(_)));
280 },
281 );
282
283 tokio::time::sleep(std::time::Duration::from_millis(50)).await;
285 group.cancel().await;
286 });
287 }
288
289 #[cfg(feature = "smol")]
290 #[test]
291 fn test_task_group_with_smol_executor() {
292 let ex = Arc::new(smol::Executor::new());
293 smol::block_on(ex.clone().run(async move {
294 let group = Arc::new(TaskGroup::with_executor(ex.into()));
295
296 group.spawn_then(future::ready(0), |res| async move {
297 assert!(matches!(res, TaskResult::Completed(0)));
298 });
299
300 group.spawn_then(future::pending::<()>(), |res| async move {
301 assert!(matches!(res, TaskResult::Cancelled));
302 });
303
304 let groupc = group.clone();
305 group.spawn_then(
306 async move {
307 groupc.spawn_then(future::pending::<()>(), |res| async move {
308 assert!(matches!(res, TaskResult::Cancelled));
309 });
310 },
311 |res| async move {
312 assert!(matches!(res, TaskResult::Completed(_)));
313 },
314 );
315
316 smol::Timer::after(std::time::Duration::from_millis(50)).await;
318 group.cancel().await;
319 }));
320 }
321
322 #[test]
323 fn test_task_group() {
324 block_on(async {
325 let group = Arc::new(TaskGroup::new());
326
327 group.spawn_then(future::ready(0), |res| async move {
328 assert!(matches!(res, TaskResult::Completed(0)));
329 });
330
331 group.spawn_then(future::pending::<()>(), |res| async move {
332 assert!(matches!(res, TaskResult::Cancelled));
333 });
334
335 let groupc = group.clone();
336 group.spawn_then(
337 async move {
338 groupc.spawn_then(future::pending::<()>(), |res| async move {
339 assert!(matches!(res, TaskResult::Cancelled));
340 });
341 },
342 |res| async move {
343 assert!(matches!(res, TaskResult::Completed(_)));
344 },
345 );
346
347 sleep(std::time::Duration::from_millis(50)).await;
349 group.cancel().await;
350 });
351 }
352
353 #[test]
354 fn test_task_group_removes_finished_tasks() {
355 block_on(async {
356 let group = Arc::new(TaskGroup::new());
357
358 group.spawn(future::ready(0));
360 group.spawn(future::pending::<()>());
361
362 sleep(std::time::Duration::from_millis(50)).await;
363 assert_eq!(group.len(), 1);
364
365 group.cancel().await;
366 assert!(group.is_empty());
367 });
368 }
369
370 #[test]
371 fn test_task_group_remove_by_id() {
372 block_on(async {
373 let group = Arc::new(TaskGroup::new());
374
375 let id = group.spawn(future::pending::<()>());
376 assert_eq!(group.len(), 1);
377
378 let handler = group.remove(id).expect("task is present");
379 assert!(group.is_empty());
380 handler.cancel().await;
381 });
382 }
383}