@@ -6,12 +6,15 @@ use core::mem;
6
6
use core:: pin:: Pin ;
7
7
use futures_core:: future:: { Future , TryFuture } ;
8
8
use futures_core:: task:: { Context , Poll } ;
9
+ use rand:: prelude:: SliceRandom ;
10
+ use rand:: rngs:: SmallRng ;
9
11
10
12
/// Future for the [`select_ok`] function.
11
13
#[ derive( Debug ) ]
12
14
#[ must_use = "futures do nothing unless you `.await` or poll them" ]
13
15
pub struct SelectOk < Fut > {
14
16
inner : Vec < Fut > ,
17
+ rng : SmallRng ,
15
18
}
16
19
17
20
impl < Fut : Unpin > Unpin for SelectOk < Fut > { }
@@ -26,6 +29,17 @@ impl<Fut: Unpin> Unpin for SelectOk<Fut> {}
26
29
/// This function is only available when the `std` or `alloc` feature of this
27
30
/// library is activated, and it is activated by default.
28
31
///
32
+ /// # Note for users migrating from 0.3 to 0.4
33
+ ///
34
+ /// This function used to be biased in favor of futures that appeared earlier in the
35
+ /// iterator. This is no longer the case, the futures are now shuffled prior to being polled.
36
+ /// This prevents starvation problems. It also has the side effect that the returned `Vec`
37
+ /// of remaining futures may be longer than it was in version 0.3, because of this shuffling.
38
+ /// Some futures that would have been polled and had errors get dropped, may now instead
39
+ /// remain in the collection without being polled.
40
+ ///
41
+ /// If you were relying on this biased behavior, consider switching to the [`select_biased!`](crate::select_biased) macro.
42
+ ///
29
43
/// # Panics
30
44
///
31
45
/// This function will panic if the iterator specified contains no items.
34
48
I : IntoIterator ,
35
49
I :: Item : TryFuture + Unpin ,
36
50
{
37
- let ret = SelectOk { inner : iter. into_iter ( ) . collect ( ) } ;
51
+ let ret = SelectOk { inner : iter. into_iter ( ) . collect ( ) , rng : crate :: gen_rng ( ) } ;
38
52
assert ! ( !ret. inner. is_empty( ) , "iterator provided to select_ok was empty" ) ;
39
53
assert_future :: <
40
54
Result < ( <I :: Item as TryFuture >:: Ok , Vec < I :: Item > ) , <I :: Item as TryFuture >:: Error > ,
@@ -46,24 +60,25 @@ impl<Fut: TryFuture + Unpin> Future for SelectOk<Fut> {
46
60
type Output = Result < ( Fut :: Ok , Vec < Fut > ) , Fut :: Error > ;
47
61
48
62
fn poll ( mut self : Pin < & mut Self > , cx : & mut Context < ' _ > ) -> Poll < Self :: Output > {
63
+ let Self { inner, rng } = & mut * self ;
64
+ inner. shuffle ( rng) ;
49
65
// loop until we've either exhausted all errors, a success was hit, or nothing is ready
50
66
loop {
51
- let item =
52
- self . inner . iter_mut ( ) . enumerate ( ) . find_map ( |( i, f) | match f. try_poll_unpin ( cx) {
53
- Poll :: Pending => None ,
54
- Poll :: Ready ( e) => Some ( ( i, e) ) ,
55
- } ) ;
67
+ let item = inner. iter_mut ( ) . enumerate ( ) . find_map ( |( i, f) | match f. try_poll_unpin ( cx) {
68
+ Poll :: Pending => None ,
69
+ Poll :: Ready ( e) => Some ( ( i, e) ) ,
70
+ } ) ;
56
71
match item {
57
72
Some ( ( idx, res) ) => {
58
73
// always remove Ok or Err, if it's not the last Err continue looping
59
- drop ( self . inner . remove ( idx) ) ;
74
+ drop ( inner. remove ( idx) ) ;
60
75
match res {
61
76
Ok ( e) => {
62
77
let rest = mem:: take ( & mut self . inner ) ;
63
78
return Poll :: Ready ( Ok ( ( e, rest) ) ) ;
64
79
}
65
80
Err ( e) => {
66
- if self . inner . is_empty ( ) {
81
+ if inner. is_empty ( ) {
67
82
return Poll :: Ready ( Err ( e) ) ;
68
83
}
69
84
}
0 commit comments