use super::assert_future; use crate::future::TryFutureExt; use alloc::vec::Vec; use core::iter::FromIterator; use core::mem; use core::pin::Pin; use futures_core::future::{Future, TryFuture}; use futures_core::task::{Context, Poll}; /// Future for the [`select_ok`] function. #[derive(Debug)] #[must_use = "futures do nothing unless you `.await` or poll them"] pub struct SelectOk { inner: Vec, } impl Unpin for SelectOk {} /// Creates a new future which will select the first successful future over a list of futures. /// /// The returned future will wait for any future within `iter` to be ready and Ok. Unlike /// `select_all`, this will only return the first successful completion, or the last /// failure. This is useful in contexts where any success is desired and failures /// are ignored, unless all the futures fail. /// /// This function is only available when the `std` or `alloc` feature of this /// library is activated, and it is activated by default. /// /// # Panics /// /// This function will panic if the iterator specified contains no items. pub fn select_ok(iter: I) -> SelectOk where I: IntoIterator, I::Item: TryFuture + Unpin, { let ret = SelectOk { inner: iter.into_iter().collect() }; assert!(!ret.inner.is_empty(), "iterator provided to select_ok was empty"); assert_future::< Result<(::Ok, Vec), ::Error>, _, >(ret) } impl Future for SelectOk { type Output = Result<(Fut::Ok, Vec), Fut::Error>; fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll { // loop until we've either exhausted all errors, a success was hit, or nothing is ready loop { let item = self.inner.iter_mut().enumerate().find_map(|(i, f)| match f.try_poll_unpin(cx) { Poll::Pending => None, Poll::Ready(e) => Some((i, e)), }); match item { Some((idx, res)) => { // always remove Ok or Err, if it's not the last Err continue looping drop(self.inner.remove(idx)); match res { Ok(e) => { let rest = mem::replace(&mut self.inner, Vec::new()); return Poll::Ready(Ok((e, rest))); } Err(e) => { if self.inner.is_empty() { return Poll::Ready(Err(e)); } } } } None => { // based on the filter above, nothing is ready, return return Poll::Pending; } } } } } impl FromIterator for SelectOk { fn from_iter>(iter: T) -> Self { select_ok(iter) } }