use std::{future::Future, mem::MaybeUninit}; trait AsyncArrayMap { async fn async_map(self, f: F) -> [U; N] where F: FnMut(T) -> Fut, Fut: Future; } impl AsyncArrayMap for [T; N] { async fn async_map(self, mut f: F) -> [U; N] where F: FnMut(T) -> Fut, Fut: Future, { let mut out: [MaybeUninit; N] = unsafe { MaybeUninit::uninit().assume_init() }; for (i, v) in self.into_iter().enumerate() { out[i].write(f(v).await); } unsafe { std::mem::transmute_copy(&out) } } } /// Wrapper around an array of JoinHandles to provide better error reporting & shutdown. pub struct Tasks(pub [tokio::task::JoinHandle>; S]); impl, const S: usize> Tasks { /// Abort tasks, and report either errors thrown from within each task /// or from tokio about joining the task. pub async fn shutdown(self) -> [crate::Result<()>; S] { self.0 .async_map(async |handle| { if !handle.is_finished() { handle.abort(); } match handle.await { Ok(Err(error)) => Err(error.into()), Err(error) if !error.is_cancelled() => Err(crate::Error::JoinError(error)), Ok(Ok(())) | Err(_) => Ok(()), } }) .await } }