futures_concurrency/future/race/
tuple.rs

1use super::Race as RaceTrait;
2use crate::utils;
3
4use core::fmt::{self, Debug};
5use core::future::{Future, IntoFuture};
6use core::pin::Pin;
7use core::task::{Context, Poll};
8
9use pin_project::pin_project;
10
11macro_rules! impl_race_tuple {
12    ($StructName:ident $($F:ident)+) => {
13        /// A future which waits for the first future to complete.
14        ///
15        /// This `struct` is created by the [`race`] method on the [`Race`] trait. See
16        /// its documentation for more.
17        ///
18        /// [`race`]: crate::future::Race::race
19        /// [`Race`]: crate::future::Race
20        #[pin_project]
21        #[must_use = "futures do nothing unless you `.await` or poll them"]
22        #[allow(non_snake_case)]
23        pub struct $StructName<T, $($F),*>
24        where $(
25            $F: Future<Output = T>,
26        )* {
27            done: bool,
28            indexer: utils::Indexer,
29            $(#[pin] $F: $F,)*
30        }
31
32        impl<T, $($F),*> Debug for $StructName<T, $($F),*>
33        where $(
34            $F: Future<Output = T> + Debug,
35        )* {
36            fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
37                f.debug_tuple("Race")
38                    $(.field(&self.$F))*
39                    .finish()
40            }
41        }
42
43        impl<T, $($F),*> RaceTrait for ($($F,)*)
44        where $(
45            $F: IntoFuture<Output = T>,
46        )* {
47            type Output = T;
48            type Future = $StructName<T, $($F::IntoFuture),*>;
49
50            fn race(self) -> Self::Future {
51                let ($($F,)*): ($($F,)*) = self;
52                $StructName {
53                    done: false,
54                    indexer: utils::Indexer::new(utils::tuple_len!($($F,)*)),
55                    $($F: $F.into_future()),*
56                }
57            }
58        }
59
60        impl<T, $($F: Future),*> Future for $StructName<T, $($F),*>
61        where
62            $($F: Future<Output = T>),*
63        {
64            type Output = T;
65
66            fn poll(
67                self: Pin<&mut Self>, cx: &mut Context<'_>
68            ) -> Poll<Self::Output> {
69                let mut this = self.project();
70                assert!(!*this.done, "Futures must not be polled after completing");
71
72                #[repr(usize)]
73                enum Indexes {
74                    $($F),*
75                }
76
77                for i in this.indexer.iter() {
78                    utils::gen_conditions!(i, this, cx, poll, $((Indexes::$F as usize; $F, {
79                        Poll::Ready(output) => {
80                            *this.done = true;
81                            return Poll::Ready(output);
82                        },
83                        _ => continue,
84                    }))*);
85                }
86
87                Poll::Pending
88            }
89        }
90    };
91}
92
93impl_race_tuple! { Race1 A }
94impl_race_tuple! { Race2 A B }
95impl_race_tuple! { Race3 A B C }
96impl_race_tuple! { Race4 A B C D }
97impl_race_tuple! { Race5 A B C D E }
98impl_race_tuple! { Race6 A B C D E F }
99impl_race_tuple! { Race7 A B C D E F G }
100impl_race_tuple! { Race8 A B C D E F G H }
101impl_race_tuple! { Race9 A B C D E F G H I }
102impl_race_tuple! { Race10 A B C D E F G H I J }
103impl_race_tuple! { Race11 A B C D E F G H I J K }
104impl_race_tuple! { Race12 A B C D E F G H I J K L }
105
106#[cfg(test)]
107mod test {
108    use super::*;
109    use core::future;
110
111    #[test]
112    fn race_1() {
113        futures_lite::future::block_on(async {
114            let a = future::ready("world");
115            assert_eq!((a,).race().await, "world");
116        });
117    }
118
119    #[test]
120    fn race_2() {
121        futures_lite::future::block_on(async {
122            let a = future::pending();
123            let b = future::ready("world");
124            assert_eq!((a, b).race().await, "world");
125        });
126    }
127
128    #[test]
129    fn race_3() {
130        futures_lite::future::block_on(async {
131            let a = future::pending();
132            let b = future::ready("hello");
133            let c = future::ready("world");
134            let result = (a, b, c).race().await;
135            assert!(matches!(result, "hello" | "world"));
136        });
137    }
138}