use alloc::vec::Vec;
use core::future::Future;
use core::marker::Unpin;
use core::pin::Pin;
use core::task::{Context, Poll, RawWaker, RawWakerVTable, Waker};
pub(crate) enum ResultFuture<F: Future<Output = O> + Unpin, O> {
Pending(F),
Ready(O),
}
pub(crate) struct TwoFutureJoiner<
AO,
BO,
AF: Future<Output = AO> + Unpin,
BF: Future<Output = BO> + Unpin,
> {
a: Option<ResultFuture<AF, AO>>,
b: Option<ResultFuture<BF, BO>>,
}
impl<AO, BO, AF: Future<Output = AO> + Unpin, BF: Future<Output = BO> + Unpin>
TwoFutureJoiner<AO, BO, AF, BF>
{
pub fn new(future_a: AF, future_b: BF) -> Self {
Self { a: Some(ResultFuture::Pending(future_a)), b: Some(ResultFuture::Pending(future_b)) }
}
}
impl<AO, BO, AF: Future<Output = AO> + Unpin, BF: Future<Output = BO> + Unpin> Future
for TwoFutureJoiner<AO, BO, AF, BF>
{
type Output = (AO, BO);
fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<(AO, BO)> {
let mut have_pending_futures = false;
let state = unsafe { &mut self.get_unchecked_mut() };
macro_rules! poll_future {
($future: ident) => {
match state.$future {
Some(ResultFuture::Pending(ref mut fut)) => match Pin::new(fut).poll(cx) {
Poll::Ready(res) => {
state.$future = Some(ResultFuture::Ready(res));
},
Poll::Pending => {
have_pending_futures = true;
},
},
Some(ResultFuture::Ready(_)) => {},
None => {
debug_assert!(false, "Future polled after Ready");
return Poll::Pending;
},
}
};
}
poll_future!(a);
poll_future!(b);
if have_pending_futures {
Poll::Pending
} else {
Poll::Ready((
match state.a.take() {
Some(ResultFuture::Ready(a)) => a,
_ => unreachable!(),
},
match state.b.take() {
Some(ResultFuture::Ready(b)) => b,
_ => unreachable!(),
},
))
}
}
}
pub(crate) struct MultiResultFuturePoller<F: Future<Output = O> + Unpin, O> {
futures_state: Vec<ResultFuture<F, O>>,
}
impl<F: Future<Output = O> + Unpin, O> MultiResultFuturePoller<F, O> {
pub fn new(futures_state: Vec<ResultFuture<F, O>>) -> Self {
Self { futures_state }
}
}
impl<F: Future<Output = O> + Unpin, O> Future for MultiResultFuturePoller<F, O> {
type Output = Vec<O>;
fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Vec<O>> {
let mut have_pending_futures = false;
let futures_state = unsafe { &mut self.get_unchecked_mut().futures_state };
for state in futures_state.iter_mut() {
match state {
ResultFuture::Pending(ref mut fut) => match Pin::new(fut).poll(cx) {
Poll::Ready(res) => {
*state = ResultFuture::Ready(res);
},
Poll::Pending => {
have_pending_futures = true;
},
},
ResultFuture::Ready(_) => continue,
}
}
if have_pending_futures {
Poll::Pending
} else {
let results = futures_state
.drain(..)
.filter_map(|e| match e {
ResultFuture::Ready(res) => Some(res),
ResultFuture::Pending(_) => {
debug_assert!(
false,
"All futures are expected to be ready if none are pending"
);
None
},
})
.collect();
Poll::Ready(results)
}
}
}
fn dummy_waker_clone(_: *const ()) -> RawWaker {
RawWaker::new(core::ptr::null(), &DUMMY_WAKER_VTABLE)
}
fn dummy_waker_action(_: *const ()) {}
const DUMMY_WAKER_VTABLE: RawWakerVTable = RawWakerVTable::new(
dummy_waker_clone,
dummy_waker_action,
dummy_waker_action,
dummy_waker_action,
);
pub(crate) fn dummy_waker() -> Waker {
unsafe { Waker::from_raw(RawWaker::new(core::ptr::null(), &DUMMY_WAKER_VTABLE)) }
}