completion/future/join/tuple/
race_ok.rs

1use core::marker::PhantomData;
2use core::pin::Pin;
3use core::task::{Context, Poll};
4
5use completion_core::CompletionFuture;
6use pin_project_lite::pin_project;
7
8use super::super::{ControlFlow, RaceOkFuture, TryFuture};
9use super::base::{Join, JoinTuple};
10
11/// Wait for the first future in a tuple to successfully complete.
12///
13/// Requires the `std` feature, as [`std::panic::catch_unwind`] is needed when polling the futures
14/// to ensure soundness.
15///
16/// # Examples
17///
18/// ```
19/// use completion::{future, completion_async};
20/// use futures_lite::future::yield_now;
21///
22/// # future::block_on(completion_async! {
23/// assert_eq!(
24///     future::race_ok((
25///         completion_async!(Err(())),
26///         completion_async!(Ok::<_, ()>(3)),
27///         std::future::pending::<Result<_, ()>>(),
28///     ))
29///     .await,
30///     Ok(3),
31/// );
32/// # });
33/// ```
34///
35/// If all the futures fail, this will return a tuple of the errors.
36///
37/// ```
38/// use completion::{future, completion_async};
39/// use futures_lite::future::yield_now;
40///
41/// # future::block_on(completion_async! {
42/// assert_eq!(
43///     future::race_ok((
44///         completion_async!(Err::<(), _>(0)),
45///         completion_async!(Err(1)),
46///         completion_async!(Err(2)),
47///     ))
48///     .await,
49///     Err((0, 1, 2)),
50/// );
51/// # });
52/// ```
53///
54/// If multiple futures are immediately successfully ready, the earlier one will be chosen. However
55/// after this polling will be fair.
56///
57/// ```
58/// use completion::{future, completion_async};
59/// use futures_lite::future::yield_now;
60///
61/// # future::block_on(completion_async! {
62/// assert_eq!(
63///     future::race_ok((
64///         completion_async! {
65///             yield_now().await;
66///             Ok::<_, ()>(0)
67///         },
68///         completion_async!(Ok::<_, ()>(1)),
69///         completion_async!(Err(2)),
70///         completion_async!(Ok::<_, ()>(3)),
71///     ))
72///     .await,
73///     Ok(1),
74/// );
75/// # });
76/// ```
77#[cfg_attr(doc_cfg, doc(cfg(feature = "std")))]
78pub fn race_ok<T: RaceOkTuple>(futures: T) -> RaceOk<T> {
79    RaceOk {
80        inner: Join::new(futures.into_tuple()),
81        _correct_debug_bounds: PhantomData,
82    }
83}
84
85pin_project! {
86    /// Future for [`race_ok`].
87    #[cfg_attr(doc_cfg, doc(cfg(feature = "std")))]
88    #[derive(Debug)]
89    pub struct RaceOk<T: RaceOkTuple> {
90        #[pin]
91        inner: Join<T::JoinTuple>,
92        _correct_debug_bounds: PhantomData<(T::Futures, T::Ok)>,
93    }
94}
95
96impl<T: RaceOkTuple> CompletionFuture for RaceOk<T> {
97    type Output = Result<T::Ok, <T::JoinTuple as JoinTuple>::Output>;
98
99    unsafe fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
100        self.project().inner.poll(cx).map(|flow| match flow {
101            ControlFlow::Continue(errors) => Err(errors),
102            ControlFlow::Break(val) => Ok(val),
103        })
104    }
105    unsafe fn poll_cancel(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<()> {
106        self.project().inner.poll_cancel(cx)
107    }
108}
109
110/// A tuple of futures that can be used in `RaceOk`.
111pub trait RaceOkTuple {
112    /// The tuple that can be used with `Join`.
113    type JoinTuple: JoinTuple<Futures = Self::Futures, Break = Self::Ok>;
114    fn into_tuple(self) -> Self::JoinTuple;
115
116    type Futures;
117    type Ok;
118}
119
120macro_rules! impl_race_tuple {
121    ($($param:ident),*) => {
122        impl<Ok, $($param,)*> RaceOkTuple for ($($param,)*)
123        where
124            $($param: TryFuture<Ok = Ok>,)*
125        {
126            type JoinTuple = ($(RaceOkFuture<$param>,)*);
127            fn into_tuple(self) -> Self::JoinTuple {
128                let ($($param,)*) = self;
129                ($(RaceOkFuture::new($param),)*)
130            }
131
132            type Futures = <Self::JoinTuple as JoinTuple>::Futures;
133            type Ok = Ok;
134        }
135    }
136}
137apply_on_tuples!(impl_race_tuple!);