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