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}