use std::future::Future;
use std::marker::Unpin;
use std::pin::Pin;
use std::task::{Context, Poll};
pub(crate) struct FutureVector<R, E, F: Future<Output = Result<R, E>> + Unpin> {
vec: Vec<F>,
}
pub(crate) struct FutureVectorSelect<'a, R, E, F: Future<Output = Result<R, E>> + Unpin>(
&'a mut FutureVector<R, E, F>,
);
pub(crate) struct FutureVectorDiscardingJoin<'a, R, E, F: Future<Output = Result<R, E>> + Unpin>(
&'a mut FutureVector<R, E, F>,
);
impl<R, E, F: Future<Output = Result<R, E>> + Unpin> FutureVector<R, E, F> {
pub fn new() -> Self {
FutureVector { vec: Vec::new() }
}
pub fn push(&mut self, future: F) {
self.vec.push(future);
}
pub fn is_empty(&self) -> bool {
self.vec.is_empty()
}
pub fn len(&self) -> usize {
self.vec.len()
}
pub fn select(&mut self) -> FutureVectorSelect<'_, R, E, F> {
FutureVectorSelect(self)
}
pub fn discarding_join(&mut self) -> FutureVectorDiscardingJoin<'_, R, E, F> {
FutureVectorDiscardingJoin(self)
}
}
impl<R, E, F: Future<Output = Result<R, E>> + Unpin> Future for FutureVectorSelect<'_, R, E, F> {
type Output = F::Output;
fn poll(mut self: Pin<&mut Self>, ctx: &mut Context<'_>) -> Poll<F::Output> {
assert!(!self.0.is_empty());
for (i, fut) in self.0.vec.iter_mut().enumerate() {
if let Poll::Ready(result) = F::poll(Pin::new(fut), ctx) {
self.0.vec.swap_remove(i);
return Poll::Ready(result);
}
}
Poll::Pending
}
}
impl<R, E, F: Future<Output = Result<R, E>> + Unpin> Future
for FutureVectorDiscardingJoin<'_, R, E, F>
{
type Output = Result<(), E>;
fn poll(mut self: Pin<&mut Self>, ctx: &mut Context<'_>) -> Poll<Result<(), E>> {
let mut i = 0;
while i < self.0.len() {
if let Poll::Ready(result) = F::poll(Pin::new(&mut self.0.vec[i]), ctx) {
self.0.vec.swap_remove(i);
if let Err(err) = result {
return Poll::Ready(Err(err));
}
} else {
i += 1;
}
}
if self.0.is_empty() {
Poll::Ready(Ok(()))
} else {
Poll::Pending
}
}
}