use std::future::Future;
use std::marker::PhantomData;
use std::mem::take;
use std::pin::Pin;
use std::task::{Context, Poll};
pub(crate) type BoxFuture<'a, T> = Pin<Box<dyn Future<Output = T> + Send + 'a>>;
pub(crate) fn try_join_all<K, Fut, T, E>(items: Vec<(K, Fut)>) -> TryJoinAll<K, Fut, T, E>
where
Fut: Future<Output = Result<T, E>> + Unpin,
{
TryJoinAll {
inflight: items,
done: Vec::new(),
_ty: PhantomData,
}
}
pub(crate) struct TryJoinAll<K, Fut, T, E> {
inflight: Vec<(K, Fut)>,
done: Vec<(K, T)>,
_ty: PhantomData<E>,
}
impl<K, Fut, T, E> Future for TryJoinAll<K, Fut, T, E>
where
K: Unpin,
Fut: Future<Output = Result<T, E>> + Unpin,
T: Unpin,
E: Unpin,
{
type Output = Result<Vec<(K, T)>, E>;
fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
let this = self.get_mut();
let mut i = 0;
while i < this.inflight.len() {
match Pin::new(&mut this.inflight[i].1).poll(cx) {
Poll::Ready(Ok(value)) => {
let (key, _) = this.inflight.swap_remove(i);
this.done.push((key, value));
}
Poll::Ready(Err(err)) => {
this.inflight.clear();
return Poll::Ready(Err(err));
}
Poll::Pending => i += 1,
}
}
if this.inflight.is_empty() {
Poll::Ready(Ok(take(&mut this.done)))
} else {
Poll::Pending
}
}
}