1 | use super::assert_future; |
2 | use crate::future::FutureExt; |
3 | use alloc::vec::Vec; |
4 | use core::iter::FromIterator; |
5 | use core::mem; |
6 | use core::pin::Pin; |
7 | use futures_core::future::Future; |
8 | use futures_core::task::{Context, Poll}; |
9 | |
10 | /// Future for the [`select_all`] function. |
11 | #[derive(Debug)] |
12 | #[must_use = "futures do nothing unless you `.await` or poll them" ] |
13 | pub struct SelectAll<Fut> { |
14 | inner: Vec<Fut>, |
15 | } |
16 | |
17 | impl<Fut: Unpin> Unpin for SelectAll<Fut> {} |
18 | |
19 | /// Creates a new future which will select over a list of futures. |
20 | /// |
21 | /// The returned future will wait for any future within `iter` to be ready. Upon |
22 | /// completion the item resolved will be returned, along with the index of the |
23 | /// future that was ready and the list of all the remaining futures. |
24 | /// |
25 | /// There are no guarantees provided on the order of the list with the remaining |
26 | /// futures. They might be swapped around, reversed, or completely random. |
27 | /// |
28 | /// This function is only available when the `std` or `alloc` feature of this |
29 | /// library is activated, and it is activated by default. |
30 | /// |
31 | /// # Panics |
32 | /// |
33 | /// This function will panic if the iterator specified contains no items. |
34 | pub fn select_all<I>(iter: I) -> SelectAll<I::Item> |
35 | where |
36 | I: IntoIterator, |
37 | I::Item: Future + Unpin, |
38 | { |
39 | let ret = SelectAll { inner: iter.into_iter().collect() }; |
40 | assert!(!ret.inner.is_empty()); |
41 | assert_future::<(<I::Item as Future>::Output, usize, Vec<I::Item>), _>(ret) |
42 | } |
43 | |
44 | impl<Fut> SelectAll<Fut> { |
45 | /// Consumes this combinator, returning the underlying futures. |
46 | pub fn into_inner(self) -> Vec<Fut> { |
47 | self.inner |
48 | } |
49 | } |
50 | |
51 | impl<Fut: Future + Unpin> Future for SelectAll<Fut> { |
52 | type Output = (Fut::Output, usize, Vec<Fut>); |
53 | |
54 | fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> { |
55 | let item = self.inner.iter_mut().enumerate().find_map(|(i, f)| match f.poll_unpin(cx) { |
56 | Poll::Pending => None, |
57 | Poll::Ready(e) => Some((i, e)), |
58 | }); |
59 | match item { |
60 | Some((idx, res)) => { |
61 | #[allow (clippy::let_underscore_future)] |
62 | let _ = self.inner.swap_remove(idx); |
63 | let rest = mem::take(&mut self.inner); |
64 | Poll::Ready((res, idx, rest)) |
65 | } |
66 | None => Poll::Pending, |
67 | } |
68 | } |
69 | } |
70 | |
71 | impl<Fut: Future + Unpin> FromIterator<Fut> for SelectAll<Fut> { |
72 | fn from_iter<T: IntoIterator<Item = Fut>>(iter: T) -> Self { |
73 | select_all(iter) |
74 | } |
75 | } |
76 | |