| 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 = 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: Option<(usize, ::Output)> = self.inner.iter_mut().enumerate().find_map(|(i: usize, f: &mut Fut)| match f.poll_unpin(cx) { |
| 56 | Poll::Pending => None, |
| 57 | Poll::Ready(e: ::Output) => Some((i, e)), |
| 58 | }); |
| 59 | match item { |
| 60 | Some((idx: usize, res: ::Output)) => { |
| 61 | #[allow (clippy::let_underscore_future)] |
| 62 | let _ = self.inner.swap_remove(index:idx); |
| 63 | let rest: Vec = 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 | |