use core::{future::Future, pin::Pin, task::{Context, Poll}};
pub struct JoinedPair<L, R>
where
L: Future,
R: Future
{
left: MaybeDone<L>,
right: MaybeDone<R>
}
impl<L, R> JoinedPair<L, R>
where
L: Future,
R: Future
{
pub fn new(left: L, right: R) -> Self
{
Self {
left: MaybeDone::Future(left),
right: MaybeDone::Future(right)
}
}
}
impl<L, R> Future for JoinedPair<L, R>
where
L: Future,
R: Future
{
type Output = (<L as Future>::Output, <R as Future>::Output);
fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output>
{
if unsafe {
!self.as_mut()
.map_unchecked_mut(|join| &mut join.left)
.poll(cx)
.is_ready()
|| !self.as_mut()
.map_unchecked_mut(|join| &mut join.right)
.poll(cx)
.is_ready()
}
{
return Poll::Pending
}
let join = unsafe {
self.as_mut()
.get_unchecked_mut()
};
Poll::Ready((
join.left.take_output().unwrap(),
join.right.take_output().unwrap()
))
}
}
enum MaybeDone<F: Future>
{
Future(F),
Done(F::Output),
Taken,
}
impl<F: Future> MaybeDone<F>
{
pub fn take_output(&mut self) -> Option<F::Output>
{
match *self
{
MaybeDone::Done(_) => match core::mem::replace(self, Self::Taken)
{
MaybeDone::Done(val) => Some(val),
_ => unreachable!(),
},
_ => None,
}
}
}
impl<F: Future> Future for MaybeDone<F>
{
type Output = ();
fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output>
{
unsafe {
match *self.as_mut().get_unchecked_mut()
{
MaybeDone::Future(ref mut f) => {
let val = core::task::ready!(Pin::new_unchecked(f).poll(cx));
self.set(Self::Done(val));
}
MaybeDone::Done(_) => {}
MaybeDone::Taken => unreachable!(),
}
}
Poll::Ready(())
}
}