futures_concurrency/future/race/
array.rs

1use 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/// A future which waits for the first future to complete.
13///
14/// This `struct` is created by the [`race`] method on the [`Race`] trait. See
15/// its documentation for more.
16///
17/// [`race`]: crate::future::Race::race
18/// [`Race`]: crate::future::Race
19#[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    // NOTE: we should probably poll in random order.
87    #[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}