Skip to content

Commit f73ee77

Browse files
committed
Use types to represent a select strategy instead of a boolean
1 parent bc57a82 commit f73ee77

File tree

5 files changed

+67
-32
lines changed

5 files changed

+67
-32
lines changed

Diff for: futures-util/src/future/mod.rs

+3
Original file line numberDiff line numberDiff line change
@@ -82,6 +82,9 @@ mod join_all;
8282
#[cfg(feature = "alloc")]
8383
pub use self::join_all::{join_all, JoinAll};
8484

85+
mod select_strategy;
86+
pub use select_strategy::{Biased, Fair, IsBiased};
87+
8588
mod select;
8689
pub use self::select::{select, select_biased, Select};
8790

Diff for: futures-util/src/future/select.rs

+14-12
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,19 @@
1-
use super::assert_future;
1+
use super::{assert_future, Biased, Fair, IsBiased};
22
use crate::future::{Either, FutureExt};
3+
use core::marker::PhantomData;
34
use core::pin::Pin;
45
use futures_core::future::{FusedFuture, Future};
56
use futures_core::task::{Context, Poll};
67

78
/// Future for the [`select()`] function.
89
#[must_use = "futures do nothing unless you `.await` or poll them"]
910
#[derive(Debug)]
10-
pub struct Select<A, B> {
11+
pub struct Select<A, B, BIASED = Fair> {
1112
inner: Option<(A, B)>,
12-
_biased: bool,
13+
_phantom: PhantomData<BIASED>,
1314
}
1415

15-
impl<A: Unpin, B: Unpin> Unpin for Select<A, B> {}
16+
impl<A: Unpin, B: Unpin, BIASED> Unpin for Select<A, B, BIASED> {}
1617

1718
/// Waits for either one of two differently-typed futures to complete.
1819
///
@@ -86,14 +87,14 @@ impl<A: Unpin, B: Unpin> Unpin for Select<A, B> {}
8687
/// })
8788
/// }
8889
/// ```
89-
pub fn select<A, B>(future1: A, future2: B) -> Select<A, B>
90+
pub fn select<A, B>(future1: A, future2: B) -> Select<A, B, Fair>
9091
where
9192
A: Future + Unpin,
9293
B: Future + Unpin,
9394
{
9495
assert_future::<Either<(A::Output, B), (B::Output, A)>, _>(Select {
9596
inner: Some((future1, future2)),
96-
_biased: false,
97+
_phantom: PhantomData,
9798
})
9899
}
99100

@@ -167,21 +168,22 @@ where
167168
/// })
168169
/// }
169170
/// ```
170-
pub fn select_biased<A, B>(future1: A, future2: B) -> Select<A, B>
171+
pub fn select_biased<A, B>(future1: A, future2: B) -> Select<A, B, Biased>
171172
where
172173
A: Future + Unpin,
173174
B: Future + Unpin,
174175
{
175176
assert_future::<Either<(A::Output, B), (B::Output, A)>, _>(Select {
176177
inner: Some((future1, future2)),
177-
_biased: true,
178+
_phantom: PhantomData,
178179
})
179180
}
180181

181-
impl<A, B> Future for Select<A, B>
182+
impl<A, B, BIASED> Future for Select<A, B, BIASED>
182183
where
183184
A: Future + Unpin,
184185
B: Future + Unpin,
186+
BIASED: IsBiased,
185187
{
186188
type Output = Either<(A::Output, B), (B::Output, A)>;
187189

@@ -195,7 +197,6 @@ where
195197
Some(value) => value,
196198
}
197199
}
198-
let _biased = self._biased;
199200

200201
let (a, b) = self.inner.as_mut().expect("cannot poll Select twice");
201202

@@ -208,7 +209,7 @@ where
208209
}
209210

210211
#[cfg(feature = "std")]
211-
if _biased || crate::gen_index(2) == 0 {
212+
if BIASED::IS_BIASED || crate::gen_index(2) == 0 {
212213
poll_wrap!(a, unwrap_option(self.inner.take()).1, Either::Left);
213214
poll_wrap!(b, unwrap_option(self.inner.take()).0, Either::Right);
214215
} else {
@@ -225,10 +226,11 @@ where
225226
}
226227
}
227228

228-
impl<A, B> FusedFuture for Select<A, B>
229+
impl<A, B, BIASED> FusedFuture for Select<A, B, BIASED>
229230
where
230231
A: Future + Unpin,
231232
B: Future + Unpin,
233+
BIASED: IsBiased,
232234
{
233235
fn is_terminated(&self) -> bool {
234236
self.inner.is_none()

Diff for: futures-util/src/future/select_ok.rs

+12-10
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,9 @@
11
use super::assert_future;
2+
use super::{Biased, Fair, IsBiased};
23
use crate::future::TryFutureExt;
34
use alloc::vec::Vec;
45
use core::iter::FromIterator;
6+
use core::marker::PhantomData;
57
use core::mem;
68
use core::pin::Pin;
79
use futures_core::future::{Future, TryFuture};
@@ -10,12 +12,12 @@ use futures_core::task::{Context, Poll};
1012
/// Future for the [`select_ok`] function.
1113
#[derive(Debug)]
1214
#[must_use = "futures do nothing unless you `.await` or poll them"]
13-
pub struct SelectOk<Fut> {
15+
pub struct SelectOk<Fut, BIASED = Fair> {
1416
inner: Vec<Fut>,
15-
_biased: bool,
17+
_phantom: PhantomData<BIASED>,
1618
}
1719

18-
impl<Fut: Unpin> Unpin for SelectOk<Fut> {}
20+
impl<Fut: Unpin, BIASED> Unpin for SelectOk<Fut, BIASED> {}
1921

2022
/// Creates a new future which will select the first successful future over a list of futures.
2123
///
@@ -41,12 +43,12 @@ impl<Fut: Unpin> Unpin for SelectOk<Fut> {}
4143
/// # Panics
4244
///
4345
/// This function will panic if the iterator specified contains no items.
44-
pub fn select_ok<I>(iter: I) -> SelectOk<I::Item>
46+
pub fn select_ok<I>(iter: I) -> SelectOk<I::Item, Fair>
4547
where
4648
I: IntoIterator,
4749
I::Item: TryFuture + Unpin,
4850
{
49-
let ret = SelectOk { inner: iter.into_iter().collect(), _biased: false };
51+
let ret = SelectOk { inner: iter.into_iter().collect(), _phantom: PhantomData };
5052
assert!(!ret.inner.is_empty(), "iterator provided to select_ok was empty");
5153
assert_future::<
5254
Result<(<I::Item as TryFuture>::Ok, Vec<I::Item>), <I::Item as TryFuture>::Error>,
@@ -70,27 +72,27 @@ where
7072
/// # Panics
7173
///
7274
/// This function will panic if the iterator specified contains no items.
73-
pub fn select_ok_biased<I>(iter: I) -> SelectOk<I::Item>
75+
pub fn select_ok_biased<I>(iter: I) -> SelectOk<I::Item, Biased>
7476
where
7577
I: IntoIterator,
7678
I::Item: TryFuture + Unpin,
7779
{
78-
let ret = SelectOk { inner: iter.into_iter().collect(), _biased: true };
80+
let ret = SelectOk { inner: iter.into_iter().collect(), _phantom: PhantomData };
7981
assert!(!ret.inner.is_empty(), "iterator provided to select_ok was empty");
8082
assert_future::<
8183
Result<(<I::Item as TryFuture>::Ok, Vec<I::Item>), <I::Item as TryFuture>::Error>,
8284
_,
8385
>(ret)
8486
}
8587

86-
impl<Fut: TryFuture + Unpin> Future for SelectOk<Fut> {
88+
impl<Fut: TryFuture + Unpin, BIASED: IsBiased> Future for SelectOk<Fut, BIASED> {
8789
type Output = Result<(Fut::Ok, Vec<Fut>), Fut::Error>;
8890

8991
fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
90-
let Self { inner, _biased } = &mut *self;
92+
let Self { inner, _phantom } = &mut *self;
9193
#[cfg(feature = "std")]
9294
{
93-
if !*_biased {
95+
if !BIASED::IS_BIASED {
9496
crate::shuffle(inner);
9597
}
9698
}

Diff for: futures-util/src/future/select_strategy.rs

+25
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
/// When used with a select future, this will make the future biased.
2+
/// When multiple futures are ready, the winner will be the first one
3+
/// specified.
4+
#[derive(Debug)]
5+
pub struct Biased;
6+
7+
/// When used with a select future, this will make the future fair.
8+
/// When multiple futures are ready, the winner will be pseudo-randomly
9+
/// selected. This is the default behavior.
10+
#[derive(Debug)]
11+
pub struct Fair;
12+
13+
/// Reports whether the type is an instance of [`Biased`] or not.
14+
pub trait IsBiased {
15+
/// Contains the answer to our question: is this biased?
16+
const IS_BIASED: bool;
17+
}
18+
19+
impl IsBiased for Biased {
20+
const IS_BIASED: bool = true;
21+
}
22+
23+
impl IsBiased for Fair {
24+
const IS_BIASED: bool = false;
25+
}

Diff for: futures-util/src/future/try_select.rs

+13-10
Original file line numberDiff line numberDiff line change
@@ -1,22 +1,24 @@
1+
use super::{Biased, Fair, IsBiased};
12
use crate::future::{Either, TryFutureExt};
3+
use core::marker::PhantomData;
24
use core::pin::Pin;
35
use futures_core::future::{Future, TryFuture};
46
use futures_core::task::{Context, Poll};
57

68
/// Future for the [`try_select()`] function.
79
#[must_use = "futures do nothing unless you `.await` or poll them"]
810
#[derive(Debug)]
9-
pub struct TrySelect<A, B> {
11+
pub struct TrySelect<A, B, BIASED = Fair> {
1012
inner: Option<(A, B)>,
11-
_biased: bool,
13+
_phantom: PhantomData<BIASED>,
1214
}
1315

14-
impl<A: Unpin, B: Unpin> Unpin for TrySelect<A, B> {}
16+
impl<A: Unpin, B: Unpin, BIASED> Unpin for TrySelect<A, B, BIASED> {}
1517

1618
type EitherOk<A, B> = Either<(<A as TryFuture>::Ok, B), (<B as TryFuture>::Ok, A)>;
1719
type EitherErr<A, B> = Either<(<A as TryFuture>::Error, B), (<B as TryFuture>::Error, A)>;
1820

19-
/// Waits for either one of two differently-typed futures to complete.
21+
/// Waits for either onedsfasdf of two differently-typed futures to complete.
2022
///
2123
/// This function will return a new future which awaits for either one of both
2224
/// futures to complete. The returned future will finish with both the value
@@ -55,14 +57,14 @@ type EitherErr<A, B> = Either<(<A as TryFuture>::Error, B), (<B as TryFuture>::E
5557
/// })
5658
/// }
5759
/// ```
58-
pub fn try_select<A, B>(future1: A, future2: B) -> TrySelect<A, B>
60+
pub fn try_select<A, B>(future1: A, future2: B) -> TrySelect<A, B, Fair>
5961
where
6062
A: TryFuture + Unpin,
6163
B: TryFuture + Unpin,
6264
{
6365
super::assert_future::<Result<EitherOk<A, B>, EitherErr<A, B>>, _>(TrySelect {
6466
inner: Some((future1, future2)),
65-
_biased: false,
67+
_phantom: PhantomData,
6668
})
6769
}
6870

@@ -103,21 +105,22 @@ where
103105
/// })
104106
/// }
105107
/// ```
106-
pub fn try_select_biased<A, B>(future1: A, future2: B) -> TrySelect<A, B>
108+
pub fn try_select_biased<A, B>(future1: A, future2: B) -> TrySelect<A, B, Biased>
107109
where
108110
A: TryFuture + Unpin,
109111
B: TryFuture + Unpin,
110112
{
111113
super::assert_future::<Result<EitherOk<A, B>, EitherErr<A, B>>, _>(TrySelect {
112114
inner: Some((future1, future2)),
113-
_biased: true,
115+
_phantom: PhantomData,
114116
})
115117
}
116118

117-
impl<A: Unpin, B: Unpin> Future for TrySelect<A, B>
119+
impl<A: Unpin, B: Unpin, BIASED> Future for TrySelect<A, B, BIASED>
118120
where
119121
A: TryFuture,
120122
B: TryFuture,
123+
BIASED: IsBiased,
121124
{
122125
type Output = Result<EitherOk<A, B>, EitherErr<A, B>>;
123126

@@ -142,7 +145,7 @@ where
142145

143146
#[cfg(feature = "std")]
144147
{
145-
if self._biased || crate::gen_index(2) == 0 {
148+
if BIASED::IS_BIASED || crate::gen_index(2) == 0 {
146149
poll_wrap!(a, b, Either::Left, Either::Right)
147150
} else {
148151
poll_wrap!(b, a, Either::Right, Either::Left)

0 commit comments

Comments
 (0)