use core::{future::Future, pin::Pin, task::Context, task::Poll};
pub enum SelectFuture<'b, T, A: Future<Output = T>> {
Future(&'b mut [A]),
OptFuture(&'b mut [Option<A>]),
}
impl<T, A: Future<Output = T>> core::fmt::Debug for SelectFuture<'_, T, A> {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
match self {
Self::Future(_) => write!(f, "Future"),
Self::OptFuture(_) => write!(f, "OptFuture"),
}
}
}
impl<T, A: Future<Output = T>> Future for SelectFuture<'_, T, A> {
type Output = (usize, T);
#[allow(unsafe_code)]
fn poll(
mut self: Pin<&mut Self>,
cx: &mut Context<'_>,
) -> Poll<Self::Output> {
match *self {
SelectFuture::Future(ref mut tasks) => {
let len = tasks.len();
for task_id in 0..len {
let task = &mut tasks[task_id];
let mut pin_fut =
unsafe { Pin::new_unchecked(std::ptr::read(&task)) };
let task = pin_fut.as_mut().poll(cx);
std::mem::forget(pin_fut);
match task {
Poll::Ready(ret) => return Poll::Ready((task_id, ret)),
Poll::Pending => {}
}
}
}
SelectFuture::OptFuture(ref mut tasks) => {
let len = tasks.len();
for task_id in 0..len {
if let Some(ref mut task) = tasks[task_id] {
let mut pin_fut = unsafe {
Pin::new_unchecked(std::ptr::read(&task))
};
let task = pin_fut.as_mut().poll(cx);
std::mem::forget(pin_fut);
match task {
Poll::Ready(ret) => {
tasks[task_id] = None;
return Poll::Ready((task_id, ret));
}
Poll::Pending => {}
}
}
}
}
};
Poll::Pending
}
}
pub trait Select<T, A: Future<Output = T>> {
fn select(&mut self) -> SelectFuture<'_, T, A>;
}
impl<T, A: Future<Output = T>> Select<T, A> for [A] {
fn select(&mut self) -> SelectFuture<'_, T, A> {
SelectFuture::Future(self)
}
}
impl<T, A: Future<Output = T>> Select<T, A> for [Option<A>] {
fn select(&mut self) -> SelectFuture<'_, T, A> {
SelectFuture::OptFuture(self)
}
}