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, RaceFuture};
use super::base::{Join, JoinTuple};
#[cfg_attr(doc_cfg, doc(cfg(feature = "std")))]
pub fn race<T: RaceTuple>(futures: T) -> Race<T> {
Race {
inner: Join::new(futures.into_tuple()),
_correct_debug_bounds: PhantomData,
}
}
pin_project! {
#[cfg_attr(doc_cfg, doc(cfg(feature = "std")))]
#[derive(Debug)]
pub struct Race<T: RaceTuple> {
#[pin]
inner: Join<T::JoinTuple>,
_correct_debug_bounds: PhantomData<(T::Futures, T::Output)>,
}
}
impl<T: RaceTuple> CompletionFuture for Race<T> {
type Output = T::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(_) => unreachable!(),
ControlFlow::Break(val) => val,
})
}
unsafe fn poll_cancel(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<()> {
self.project().inner.poll_cancel(cx)
}
}
pub trait RaceTuple {
type JoinTuple: JoinTuple<Futures = Self::Futures, Break = Self::Output>;
fn into_tuple(self) -> Self::JoinTuple;
type Futures;
type Output;
}
macro_rules! impl_race_tuple {
($($param:ident),*) => {
impl<Output, $($param,)*> RaceTuple for ($($param,)*)
where
$($param: CompletionFuture<Output = Output>,)*
{
type JoinTuple = ($(RaceFuture<$param>,)*);
fn into_tuple(self) -> Self::JoinTuple {
let ($($param,)*) = self;
($(RaceFuture::new($param),)*)
}
type Futures = <Self::JoinTuple as JoinTuple>::Futures;
type Output = Output;
}
}
}
apply_on_tuples!(impl_race_tuple!);