futures_util/future/
select_ok.rs

1//! Definition of the `SelectOk` combinator, finding the first successful future
2//! in a list.
3
4use std::mem;
5use std::prelude::v1::*;
6
7use futures_core::{Future, IntoFuture, Poll, Async};
8use futures_core::task;
9
10/// Future for the `select_ok` combinator, waiting for one of any of a list of
11/// futures to successfully complete. Unlike `select_all`, this future ignores all
12/// but the last error, if there are any.
13///
14/// This is created by the `select_ok` function.
15#[derive(Debug)]
16#[must_use = "futures do nothing unless polled"]
17pub struct SelectOk<A> where A: Future {
18    inner: Vec<A>,
19}
20
21/// Creates a new future which will select the first successful future over a list of futures.
22///
23/// The returned future will wait for any future within `iter` to be ready and Ok. Unlike
24/// `select_all`, this will only return the first successful completion, or the last
25/// failure. This is useful in contexts where any success is desired and failures
26/// are ignored, unless all the futures fail.
27///
28/// # Panics
29///
30/// This function will panic if the iterator specified contains no items.
31pub fn select_ok<I>(iter: I) -> SelectOk<<I::Item as IntoFuture>::Future>
32    where I: IntoIterator,
33          I::Item: IntoFuture,
34{
35    let ret = SelectOk {
36        inner: iter.into_iter()
37                   .map(|a| a.into_future())
38                   .collect(),
39    };
40    assert!(ret.inner.len() > 0);
41    ret
42}
43
44impl<A> Future for SelectOk<A> where A: Future {
45    type Item = (A::Item, Vec<A>);
46    type Error = A::Error;
47
48    fn poll(&mut self, cx: &mut task::Context) -> Poll<Self::Item, Self::Error> {
49        // loop until we've either exhausted all errors, a success was hit, or nothing is ready
50        loop {
51            let item = self.inner.iter_mut().enumerate().filter_map(|(i, f)| {
52                match f.poll(cx) {
53                    Ok(Async::Pending) => None,
54                    Ok(Async::Ready(e)) => Some((i, Ok(e))),
55                    Err(e) => Some((i, Err(e))),
56                }
57            }).next();
58
59            match item {
60                Some((idx, res)) => {
61                    // always remove Ok or Err, if it's not the last Err continue looping
62                    drop(self.inner.remove(idx));
63                    match res {
64                        Ok(e) => {
65                            let rest = mem::replace(&mut self.inner, Vec::new());
66                            return Ok(Async::Ready((e, rest)))
67                        },
68                        Err(e) => {
69                            if self.inner.is_empty() {
70                                return Err(e)
71                            }
72                        },
73                    }
74                }
75                None => {
76                    // based on the filter above, nothing is ready, return
77                    return Ok(Async::Pending)
78                },
79            }
80        }
81    }
82}