futures_concurrency/future/race/
array.rs1use crate::utils::{self, Indexer};
2
3use super::Race as RaceTrait;
4
5use core::fmt;
6use core::future::{Future, IntoFuture};
7use core::pin::Pin;
8use core::task::{Context, Poll};
9
10use pin_project::pin_project;
11
12#[must_use = "futures do nothing unless you `.await` or poll them"]
20#[pin_project]
21pub struct Race<Fut, const N: usize>
22where
23 Fut: Future,
24{
25 #[pin]
26 futures: [Fut; N],
27 indexer: Indexer,
28 done: bool,
29}
30
31impl<Fut, const N: usize> fmt::Debug for Race<Fut, N>
32where
33 Fut: Future + fmt::Debug,
34 Fut::Output: fmt::Debug,
35{
36 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
37 f.debug_list().entries(self.futures.iter()).finish()
38 }
39}
40
41impl<Fut, const N: usize> Future for Race<Fut, N>
42where
43 Fut: Future,
44{
45 type Output = Fut::Output;
46
47 fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
48 let mut this = self.project();
49 assert!(!*this.done, "Futures must not be polled after completing");
50
51 for index in this.indexer.iter() {
52 let fut = utils::get_pin_mut(this.futures.as_mut(), index).unwrap();
53 match fut.poll(cx) {
54 Poll::Ready(item) => {
55 *this.done = true;
56 return Poll::Ready(item);
57 }
58 Poll::Pending => continue,
59 }
60 }
61 Poll::Pending
62 }
63}
64
65impl<Fut, const N: usize> RaceTrait for [Fut; N]
66where
67 Fut: IntoFuture,
68{
69 type Output = Fut::Output;
70 type Future = Race<Fut::IntoFuture, N>;
71
72 fn race(self) -> Self::Future {
73 Race {
74 futures: self.map(|fut| fut.into_future()),
75 indexer: Indexer::new(N),
76 done: false,
77 }
78 }
79}
80
81#[cfg(test)]
82mod test {
83 use super::*;
84 use core::future;
85
86 #[test]
88 fn no_fairness() {
89 futures_lite::future::block_on(async {
90 let res = [future::ready("hello"), future::ready("world")]
91 .race()
92 .await;
93 assert!(matches!(res, "hello" | "world"));
94 });
95 }
96}