use core::marker::PhantomData;
use core::pin::Pin;
use core::task::{Context, Poll};
use completion_core::CompletionFuture;
use pin_project_lite::pin_project;
use super::super::{ControlFlow, RaceOkFuture, TryFuture};
use super::base::{Join, JoinTuple};
#[cfg_attr(doc_cfg, doc(cfg(feature = "std")))]
pub fn race_ok<T: RaceOkTuple>(futures: T) -> RaceOk<T> {
RaceOk {
inner: Join::new(futures.into_tuple()),
_correct_debug_bounds: PhantomData,
}
}
pin_project! {
#[cfg_attr(doc_cfg, doc(cfg(feature = "std")))]
#[derive(Debug)]
pub struct RaceOk<T: RaceOkTuple> {
#[pin]
inner: Join<T::JoinTuple>,
_correct_debug_bounds: PhantomData<(T::Futures, T::Ok)>,
}
}
impl<T: RaceOkTuple> CompletionFuture for RaceOk<T> {
type Output = Result<T::Ok, <T::JoinTuple as JoinTuple>::Output>;
unsafe fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
self.project().inner.poll(cx).map(|flow| match flow {
ControlFlow::Continue(errors) => Err(errors),
ControlFlow::Break(val) => Ok(val),
})
}
unsafe fn poll_cancel(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<()> {
self.project().inner.poll_cancel(cx)
}
}
pub trait RaceOkTuple {
type JoinTuple: JoinTuple<Futures = Self::Futures, Break = Self::Ok>;
fn into_tuple(self) -> Self::JoinTuple;
type Futures;
type Ok;
}
macro_rules! impl_race_tuple {
($($param:ident),*) => {
impl<Ok, $($param,)*> RaceOkTuple for ($($param,)*)
where
$($param: TryFuture<Ok = Ok>,)*
{
type JoinTuple = ($(RaceOkFuture<$param>,)*);
fn into_tuple(self) -> Self::JoinTuple {
let ($($param,)*) = self;
($(RaceOkFuture::new($param),)*)
}
type Futures = <Self::JoinTuple as JoinTuple>::Futures;
type Ok = Ok;
}
}
}
apply_on_tuples!(impl_race_tuple!);