1use super::assert_future;
2use crate::future::TryFutureExt;
3use alloc::vec::Vec;
4use core::iter::FromIterator;
5use core::mem;
6use core::pin::Pin;
7use futures_core::future::{Future, TryFuture};
8use futures_core::task::{Context, Poll};
9
10/// Future for the [`select_ok`] function.
11#[derive(Debug)]
12#[must_use = "futures do nothing unless you `.await` or poll them"]
13pub struct SelectOk<Fut> {
14 inner: Vec<Fut>,
15}
16
17impl<Fut: Unpin> Unpin for SelectOk<Fut> {}
18
19/// Creates a new future which will select the first successful future over a list of futures.
20///
21/// The returned future will wait for any future within `iter` to be ready and Ok. Unlike
22/// `select_all`, this will only return the first successful completion, or the last
23/// failure. This is useful in contexts where any success is desired and failures
24/// are ignored, unless all the futures fail.
25///
26/// This function is only available when the `std` or `alloc` feature of this
27/// library is activated, and it is activated by default.
28///
29/// # Panics
30///
31/// This function will panic if the iterator specified contains no items.
32pub fn select_ok<I>(iter: I) -> SelectOk<I::Item>
33where
34 I: IntoIterator,
35 I::Item: TryFuture + Unpin,
36{
37 let ret: SelectOk<::Item> = SelectOk { inner: iter.into_iter().collect() };
38 assert!(!ret.inner.is_empty(), "iterator provided to select_ok was empty");
39 assert_future::<
40 Result<(<I::Item as TryFuture>::Ok, Vec<I::Item>), <I::Item as TryFuture>::Error>,
41 _,
42 >(ret)
43}
44
45impl<Fut: TryFuture + Unpin> Future for SelectOk<Fut> {
46 type Output = Result<(Fut::Ok, Vec<Fut>), Fut::Error>;
47
48 fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
49 // loop until we've either exhausted all errors, a success was hit, or nothing is ready
50 loop {
51 let item =
52 self.inner.iter_mut().enumerate().find_map(|(i, f)| match f.try_poll_unpin(cx) {
53 Poll::Pending => None,
54 Poll::Ready(e) => Some((i, e)),
55 });
56 match item {
57 Some((idx, res)) => {
58 // always remove Ok or Err, if it's not the last Err continue looping
59 drop(self.inner.remove(idx));
60 match res {
61 Ok(e) => {
62 let rest = mem::take(&mut self.inner);
63 return Poll::Ready(Ok((e, rest)));
64 }
65 Err(e) => {
66 if self.inner.is_empty() {
67 return Poll::Ready(Err(e));
68 }
69 }
70 }
71 }
72 None => {
73 // based on the filter above, nothing is ready, return
74 return Poll::Pending;
75 }
76 }
77 }
78 }
79}
80
81impl<Fut: TryFuture + Unpin> FromIterator<Fut> for SelectOk<Fut> {
82 fn from_iter<T: IntoIterator<Item = Fut>>(iter: T) -> Self {
83 select_ok(iter)
84 }
85}
86