@@ -27,6 +27,15 @@ use self::task::Task;
27
27
mod ready_to_run_queue;
28
28
use self :: ready_to_run_queue:: { ReadyToRunQueue , Dequeue } ;
29
29
30
+ /// Constant used for a `FuturesUnordered` to indicate we are empty and have
31
+ /// yielded a `None` element so can return `true` from
32
+ /// `FusedStream::is_terminated`
33
+ ///
34
+ /// It is safe to not check for this when incrementing as even a ZST future will
35
+ /// have a `Task` allocated for it, so we cannot ever reach usize::max_value()
36
+ /// without running out of ram.
37
+ const TERMINATED_SENTINEL_LENGTH : usize = usize:: max_value ( ) ;
38
+
30
39
/// A set of futures which may complete in any order.
31
40
///
32
41
/// This structure is optimized to manage a large number of futures.
@@ -49,9 +58,6 @@ pub struct FuturesUnordered<Fut> {
49
58
ready_to_run_queue : Arc < ReadyToRunQueue < Fut > > ,
50
59
len : usize ,
51
60
head_all : * const Task < Fut > ,
52
- /// Track whether we have yielded `None` and can consider ourselves
53
- /// terminated
54
- is_terminated : bool ,
55
61
}
56
62
57
63
unsafe impl < Fut : Send > Send for FuturesUnordered < Fut > { }
@@ -126,7 +132,6 @@ impl<Fut: Future> FuturesUnordered<Fut> {
126
132
len : 0 ,
127
133
head_all : ptr:: null_mut ( ) ,
128
134
ready_to_run_queue,
129
- is_terminated : false ,
130
135
}
131
136
}
132
137
}
@@ -142,12 +147,12 @@ impl<Fut> FuturesUnordered<Fut> {
142
147
///
143
148
/// This represents the total number of in-flight futures.
144
149
pub fn len ( & self ) -> usize {
145
- self . len
150
+ if self . len == TERMINATED_SENTINEL_LENGTH { 0 } else { self . len }
146
151
}
147
152
148
153
/// Returns `true` if the set contains no futures.
149
154
pub fn is_empty ( & self ) -> bool {
150
- self . len == 0
155
+ self . len == 0 || self . len == TERMINATED_SENTINEL_LENGTH
151
156
}
152
157
153
158
/// Push a future into the set.
@@ -166,6 +171,12 @@ impl<Fut> FuturesUnordered<Fut> {
166
171
ready_to_run_queue : Arc :: downgrade ( & self . ready_to_run_queue ) ,
167
172
} ) ;
168
173
174
+ // If we've previously marked ourselves as terminated we need to reset
175
+ // len to 0 to track it correctly
176
+ if self . len == TERMINATED_SENTINEL_LENGTH {
177
+ self . len = 0 ;
178
+ }
179
+
169
180
// Right now our task has a strong reference count of 1. We transfer
170
181
// ownership of this reference count to our internal linked list
171
182
// and we'll reclaim ownership through the `unlink` method below.
@@ -176,10 +187,6 @@ impl<Fut> FuturesUnordered<Fut> {
176
187
// futures are ready. To do that we unconditionally enqueue it for
177
188
// polling here.
178
189
self . ready_to_run_queue . enqueue ( ptr) ;
179
-
180
- // If we've previously marked ourselves as terminated we need to clear
181
- // that now that we will yield a new item.
182
- self . is_terminated = false ;
183
190
}
184
191
185
192
/// Returns an iterator that allows modifying each future in the set.
@@ -192,7 +199,7 @@ impl<Fut> FuturesUnordered<Fut> {
192
199
pub fn iter_pin_mut < ' a > ( self : Pin < & ' a mut Self > ) -> IterPinMut < ' a , Fut > {
193
200
IterPinMut {
194
201
task : self . head_all ,
195
- len : self . len ,
202
+ len : self . len ( ) ,
196
203
_marker : PhantomData
197
204
}
198
205
}
@@ -294,7 +301,7 @@ impl<Fut: Future> Stream for FuturesUnordered<Fut> {
294
301
if self . is_empty ( ) {
295
302
// We can only consider ourselves terminated once we
296
303
// have yielded a `None`
297
- self . is_terminated = true ;
304
+ self . len = TERMINATED_SENTINEL_LENGTH ;
298
305
return Poll :: Ready ( None ) ;
299
306
} else {
300
307
return Poll :: Pending ;
@@ -483,6 +490,6 @@ where
483
490
484
491
impl < Fut : Future > FusedStream for FuturesUnordered < Fut > {
485
492
fn is_terminated ( & self ) -> bool {
486
- self . is_terminated
493
+ self . len == TERMINATED_SENTINEL_LENGTH
487
494
}
488
495
}
0 commit comments