use std::future::Future;
use std::pin::Pin;
use std::task::{Context, Poll};
pub(crate) fn join_all<F: Future>(futures: Vec<F>) -> JoinAll<F> {
let answers = futures.iter().map(|_| None).collect();
JoinAll {
running: futures
.into_iter()
.map(|future| Some(Box::pin(future)))
.collect(),
answers,
}
}
pub(crate) struct JoinAll<F: Future> {
running: Vec<Option<Pin<Box<F>>>>,
answers: Vec<Option<F::Output>>,
}
impl<F: Future> Unpin for JoinAll<F> {}
impl<F: Future> Future for JoinAll<F> {
type Output = Vec<F::Output>;
fn poll(self: Pin<&mut Self>, context: &mut Context<'_>) -> Poll<Self::Output> {
let this = self.get_mut();
let mut waiting = false;
for (slot, answer) in this.running.iter_mut().zip(this.answers.iter_mut()) {
let Some(future) = slot.as_mut() else {
continue;
};
match future.as_mut().poll(context) {
Poll::Ready(value) => {
*answer = Some(value);
*slot = None;
}
Poll::Pending => waiting = true,
}
}
if waiting {
return Poll::Pending;
}
Poll::Ready(
this.answers
.iter_mut()
.map(|answer| answer.take().expect("every future answered"))
.collect(),
)
}
}