use alloc::{boxed::Box, vec::Vec};
use core::{
future::Future,
mem::MaybeUninit,
pin::Pin,
task::{Context, Poll},
};
use crate::FuturesUnorderedBounded;
#[must_use = "futures do nothing unless you `.await` or poll them"]
pub struct JoinAll<F: Future> {
queue: FuturesUnorderedBounded<F>,
output: Box<[MaybeUninit<F::Output>]>,
}
impl<F: Future> Unpin for JoinAll<F> {}
pub fn join_all<I>(iter: I) -> JoinAll<<I as IntoIterator>::Item>
where
I: IntoIterator,
<I as IntoIterator>::Item: Future,
{
let queue = FuturesUnorderedBounded::from_iter(iter);
let mut output = Vec::with_capacity(queue.capacity());
output.resize_with(queue.capacity(), MaybeUninit::uninit);
JoinAll {
queue,
output: output.into_boxed_slice(),
}
}
impl<F: Future> Future for JoinAll<F> {
type Output = Vec<F::Output>;
fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
loop {
match self.as_mut().queue.poll_inner(cx) {
Poll::Ready(Some((i, x))) => {
self.output[i].write(x);
}
Poll::Ready(None) => {
let boxed = unsafe {
let boxed =
core::mem::replace(&mut self.output, Vec::new().into_boxed_slice());
let raw = Box::into_raw(boxed);
Box::from_raw(raw as *mut [F::Output])
};
break Poll::Ready(boxed.into_vec());
}
Poll::Pending => break Poll::Pending,
}
}
}
}
#[cfg(test)]
mod tests {
use core::future::ready;
#[test]
fn join_all() {
let x = futures::executor::block_on(crate::join_all((0..10).map(ready)));
assert_eq!(x.len(), 10);
assert_eq!(x.capacity(), 10);
}
}