futures_concurrency/future/race/
tuple.rs1use 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 #[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}