Skip to content

Commit 58272e3

Browse files
committed
try_select
Signed-off-by: Yoshua Wuyts <yoshuawuyts@gmail.com>
1 parent cda2ad8 commit 58272e3

File tree

3 files changed

+110
-7
lines changed

3 files changed

+110
-7
lines changed

src/future/future/mod.rs

Lines changed: 46 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,13 @@
11
cfg_unstable! {
22
mod delay;
33
mod select;
4+
mod try_select;
45

56
use std::time::Duration;
67

7-
use select::Select;
88
use delay::DelayFuture;
9+
use select::Select;
10+
use try_select::TrySelect;
911
}
1012

1113
extension_trait! {
@@ -133,7 +135,7 @@ extension_trait! {
133135
}
134136

135137
#[doc = r#"
136-
Waits for either one of several similarly-typed futures to complete.
138+
Waits for one of two similarly-typed futures to complete.
137139
138140
Awaits multiple futures simultaneously, returning all results once complete.
139141
@@ -149,7 +151,7 @@ extension_trait! {
149151
# Examples
150152
151153
```
152-
# futures::executor::block_on(async {
154+
# async_std::task::block_on(async {
153155
use async_std::prelude::*;
154156
use async_std::future;
155157
@@ -162,12 +164,51 @@ extension_trait! {
162164
# });
163165
```
164166
"#]
165-
fn select<F>(self, other: F) -> Select<Self, F>
167+
fn select<F>(self, other: F) ->
168+
impl Future<Output = Self::Output> [Select<Self, F>]
169+
where
170+
Self: Sized + Future,
171+
F: std::future::Future<Output = <Self as Future>::Output>,
172+
{
173+
Select::new(self, other)
174+
}
175+
176+
#[doc = r#"
177+
Waits for one of two similarly-typed fallible futures to complete.
178+
179+
Awaits multiple futures simultaneously, returning all results once complete.
180+
181+
`try_select` is similar to [`select`], but keeps going if a future
182+
resolved to an error until all futures have been resolved. In which case
183+
the error of the `other` future will be returned.
184+
185+
# Examples
186+
187+
```
188+
# fn main() -> std::io::Result<()> { async_std::task::block_on(async {
189+
#
190+
use async_std::prelude::*;
191+
use async_std::future;
192+
use std::io::{Error, ErrorKind};
193+
194+
let a = future::pending::<Result<_, Error>>();
195+
let b = future::ready(Err(Error::from(ErrorKind::Other)));
196+
let c = future::ready(Ok(1u8));
197+
198+
let f = a.try_select(b).try_select(c);
199+
assert_eq!(f.await?, 1u8);
200+
#
201+
# Ok(()) }) }
202+
```
203+
"#]
204+
fn try_select<F, T, E>(self, other: F) ->
205+
impl Future<Output = Self::Output> [TrySelect<Self, F>]
166206
where
167207
Self: Sized,
208+
Self: Future<Output = Result<T, E>>,
168209
F: Future<Output = Self::Output>,
169210
{
170-
Select::new(self, other)
211+
TrySelect::new(self, other)
171212
}
172213
}
173214

src/future/future/select.rs

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,7 @@ use std::pin::Pin;
33
use pin_project_lite::pin_project;
44
use async_macros::MaybeDone;
55

6-
use crate::future::Future;
7-
// use crate::future::MaybeDone;
6+
use std::future::Future;
87
use crate::task::{Context, Poll};
98

109
pin_project! {

src/future/future/try_select.rs

Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
use std::pin::Pin;
2+
3+
use async_macros::MaybeDone;
4+
use pin_project_lite::pin_project;
5+
6+
use std::future::Future;
7+
use crate::task::{Context, Poll};
8+
9+
pin_project! {
10+
#[allow(missing_docs)]
11+
#[allow(missing_debug_implementations)]
12+
pub struct TrySelect<L, R> where L: Future, R: Future<Output = L::Output> {
13+
#[pin] left: MaybeDone<L>,
14+
#[pin] right: MaybeDone<R>,
15+
}
16+
}
17+
18+
impl<L, R> TrySelect<L, R>
19+
where
20+
L: Future,
21+
R: Future<Output = L::Output>,
22+
{
23+
pub(crate) fn new(left: L, right: R) -> Self {
24+
Self {
25+
left: MaybeDone::new(left),
26+
right: MaybeDone::new(right),
27+
}
28+
}
29+
}
30+
31+
impl<L, R, T, E> Future for TrySelect<L, R>
32+
where
33+
L: Future<Output = Result<T, E>>,
34+
R: Future<Output = L::Output>,
35+
{
36+
type Output = L::Output;
37+
38+
fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
39+
let this = self.project();
40+
let mut left_errored = false;
41+
42+
// Check if the left future is ready & successful. Continue if not.
43+
let mut left = this.left;
44+
if Future::poll(Pin::new(&mut left), cx).is_ready() {
45+
if left.as_ref().output().unwrap().is_ok() {
46+
return Poll::Ready(left.take().unwrap());
47+
} else {
48+
left_errored = true;
49+
}
50+
}
51+
52+
// Check if the right future is ready & successful. Return err if left
53+
// future also resolved to err. Continue if not.
54+
let mut right = this.right;
55+
if Future::poll(Pin::new(&mut right), cx).is_ready() {
56+
if right.as_ref().output().unwrap().is_ok() || left_errored {
57+
return Poll::Ready(right.take().unwrap());
58+
}
59+
}
60+
61+
Poll::Pending
62+
}
63+
}

0 commit comments

Comments
 (0)