Skip to content

Commit 20d24a2

Browse files
committedSep 14, 2019
try_select
Signed-off-by: Yoshua Wuyts <yoshuawuyts@gmail.com>
1 parent ed083df commit 20d24a2

File tree

6 files changed

+89
-8
lines changed

6 files changed

+89
-8
lines changed
 

‎src/join.rs

-2
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,6 @@
66
/// `join!` polls both futures concurrently and therefore is more efficent.
77
///
88
/// This macro is only usable inside of async functions, closures, and blocks.
9-
/// It is also gated behind the `async-await` feature of this library, which is
10-
/// _not_ activated by default.
119
///
1210
/// # Examples
1311
///

‎src/lib.rs

+1
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ mod poll_fn;
2626
mod ready;
2727
mod select;
2828
mod try_join;
29+
mod try_select;
2930

3031
pub use maybe_done::{maybe_done, MaybeDone};
3132

‎src/maybe_done.rs

+13
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,19 @@ impl<Fut: Future> MaybeDone<Fut> {
4343
}
4444
}
4545

46+
/// Returns an [`Option`] containing a reference to the output of the future.
47+
/// The output of this method will be [`Some`] if and only if the inner
48+
/// future has been completed and [`take_output`](MaybeDone::take_output)
49+
/// has not yet been called.
50+
#[inline]
51+
pub fn output(self: Pin<&Self>) -> Option<&Fut::Output> {
52+
let this = self.get_ref();
53+
match this {
54+
MaybeDone::Done(res) => Some(res),
55+
_ => None,
56+
}
57+
}
58+
4659
/// Attempt to take the output of a `MaybeDone` without driving it
4760
/// towards completion.
4861
#[inline]

‎src/select.rs

+8-4
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,16 @@
11
#![allow(non_snake_case)]
22

3+
/// Waits for either one of several similarly-typed futures to complete.
34
/// Awaits multiple futures simultaneously, returning all results once complete.
45
///
5-
/// While `join!(a, b)` is similar to `(a.await, b.await)`,
6-
/// `join!` polls both futures concurrently and therefore is more efficent.
6+
/// This function will return a new future which awaits for either one of both
7+
/// futures to complete. If multiple futures are completed at the same time,
8+
/// resolution will occur in the order that they have been passed.
9+
///
10+
/// Note that this macro consumes all futures passed, and once a future is
11+
/// completed, all other futures are dropped.
712
///
813
/// This macro is only usable inside of async functions, closures, and blocks.
9-
/// It is also gated behind the `async-await` feature of this library, which is
10-
/// _not_ activated by default.
1114
///
1215
/// # Examples
1316
///
@@ -19,6 +22,7 @@
1922
///
2023
/// let a = future::pending();
2124
/// let b = future::ready(1u8);
25+
/// let c = future::ready(2u8);
2226
///
2327
/// assert_eq!(select!(a, b).await, 1u8);
2428
/// # });

‎src/try_join.rs

-2
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,6 @@
55
/// the futures return an error.
66
///
77
/// This macro is only usable inside of async functions, closures, and blocks.
8-
/// It is also gated behind the `async-await` feature of this library, which is
9-
/// _not_ activated by default.
108
///
119
/// # Examples
1210
///

‎src/try_select.rs

+67
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
#![allow(non_snake_case)]
2+
3+
/// Waits for either one of several similarly-typed futures to complete.
4+
/// Awaits multiple futures simultaneously, returning all results once complete.
5+
///
6+
/// `try_select!` is similar to [`select!`], but keeps going if a future
7+
/// resolved to an error until all futures have been resolved. In which case
8+
/// the last error found will be returned.
9+
///
10+
/// This macro is only usable inside of async functions, closures, and blocks.
11+
///
12+
/// # Examples
13+
///
14+
/// ```
15+
/// # futures::executor::block_on(async {
16+
/// # async fn main() -> Result<(), std::io::Error> {
17+
/// use async_macros::try_select;
18+
/// use futures::future;
19+
/// use std::io::{Error, ErrorKind};
20+
///
21+
/// let a = future::pending::<Result<u8, Error>>();
22+
/// let b = future::ready(Err(Error::from(ErrorKind::Other)));
23+
/// let c = future::ready(Ok(1u8));
24+
///
25+
/// assert_eq!(try_select!(a, b, c).await?, 1u8);
26+
/// # Ok(())
27+
/// # }
28+
/// # main().await.unwrap();
29+
/// # });
30+
/// ```
31+
#[macro_export]
32+
macro_rules! try_select {
33+
($($fut:ident),* $(,)?) => { {
34+
async {
35+
$(
36+
// Move future into a local so that it is pinned in one place and
37+
// is no longer accessible by the end user.
38+
let mut $fut = $crate::maybe_done($fut);
39+
)*
40+
$crate::utils::poll_fn(move |cx| {
41+
use $crate::utils::future::Future;
42+
use $crate::utils::task::Poll;
43+
use $crate::utils::pin::Pin;
44+
45+
let mut all_done = true;
46+
47+
$(
48+
let fut = unsafe { Pin::new_unchecked(&mut $fut) };
49+
if Future::poll(fut, cx).is_ready() {
50+
let fut = Pin::new(&$fut);
51+
if fut.output().unwrap().is_ok() {
52+
let fut = unsafe { Pin::new_unchecked(&mut $fut) };
53+
let output = fut.take_output().unwrap();
54+
return Poll::Ready(output);
55+
}
56+
}
57+
)*
58+
59+
if all_done {
60+
unimplemented!();
61+
} else {
62+
Poll::Pending
63+
}
64+
}).await
65+
}
66+
} }
67+
}

0 commit comments

Comments
 (0)