@@ -164,9 +164,9 @@ doc! {macro_rules! try_join {
164
164
#[ cfg( not( doc) ) ]
165
165
doc ! { macro_rules! try_join {
166
166
( @ {
167
- // Whether to rotate which future is polled first every poll,
168
- // by incrementing a skip counter
169
- rotate_poll_order=$rotate_poll_order : literal ;
167
+ // Type of rotator that controls which inner future to start with
168
+ // when polling our output future.
169
+ rotator=$rotator : ty ;
170
170
171
171
// One `_` for each branch in the `try_join!` macro. This is not used once
172
172
// normalization is complete.
@@ -196,102 +196,52 @@ doc! {macro_rules! try_join {
196
196
// <https://internals.rust-lang.org/t/surprising-soundness-trouble-around-pollfn/17484>
197
197
let mut futures = & mut futures;
198
198
199
+ const COUNT : u32 = $( $total) * ;
200
+
199
201
// Each time the future created by poll_fn is polled,
200
202
// if not running in biased mode,
201
203
// a different future will be polled first
202
204
// to ensure every future passed to join! gets a chance to make progress even if
203
205
// one of the futures consumes the whole budget.
204
- //
205
- // This is number of futures that will be skipped in the first loop
206
- // iteration the next time.
207
- //
208
- // If running in biased mode, this variable will be optimized out since we don't pass
209
- // it to the poll_fn.
210
- let mut skip_next_time: u32 = 0 ;
206
+ let mut rotator = <$rotator>:: default ( ) ;
211
207
212
- match $rotate_poll_order {
213
- true => poll_fn( move |cx| {
214
- const COUNT : u32 = $( $total) * ;
215
- let mut is_pending = false ;
216
- let mut to_run = COUNT ;
208
+ poll_fn( move |cx| {
209
+ let mut is_pending = false ;
210
+ let mut to_run = COUNT ;
217
211
218
- // The number of futures that will be skipped in the first loop iteration.
219
- let mut skip = skip_next_time;
220
- // Upkeep for next poll, rotate first polled future
221
- skip_next_time = if skip + 1 == COUNT { 0 } else { skip + 1 } ;
212
+ // The number of futures that will be skipped in the first loop iteration.
213
+ let mut skip = rotator. num_skip( ) ;
222
214
223
- // This loop runs twice and the first `skip` futures
224
- // are not polled in the first iteration.
225
- loop {
226
- $(
227
- if skip == 0 {
228
- if to_run == 0 {
229
- // Every future has been polled
230
- break ;
231
- }
232
- to_run -= 1 ;
215
+ // This loop runs twice and the first `skip` futures
216
+ // are not polled in the first iteration.
217
+ loop {
218
+ $(
219
+ if skip == 0 {
220
+ if to_run == 0 {
221
+ // Every future has been polled
222
+ break ;
223
+ }
224
+ to_run -= 1 ;
233
225
234
- // Extract the future for this branch from the tuple.
235
- let ( $( $skip, ) * fut, .. ) = & mut * futures;
226
+ // Extract the future for this branch from the tuple.
227
+ let ( $( $skip, ) * fut, .. ) = & mut * futures;
236
228
237
- // Safety: future is stored on the stack above
238
- // and never moved.
239
- let mut fut = unsafe { Pin :: new_unchecked( fut) } ;
229
+ // Safety: future is stored on the stack above
230
+ // and never moved.
231
+ let mut fut = unsafe { Pin :: new_unchecked( fut) } ;
240
232
241
- // Try polling
242
- if fut. as_mut( ) . poll( cx) . is_pending( ) {
243
- is_pending = true ;
244
- } else if fut. as_mut( ) . output_mut( ) . expect( "expected completed future" ) . is_err( ) {
245
- return Ready ( Err ( fut. take_output( ) . expect( "expected completed future" ) . err( ) . unwrap( ) ) )
246
- }
247
- } else {
248
- // Future skipped, one less future to skip in the next iteration
249
- skip -= 1 ;
233
+ // Try polling
234
+ if fut. as_mut( ) . poll( cx) . is_pending( ) {
235
+ is_pending = true ;
236
+ } else if fut. as_mut( ) . output_mut( ) . expect( "expected completed future" ) . is_err( ) {
237
+ return Ready ( Err ( fut. take_output( ) . expect( "expected completed future" ) . err( ) . unwrap( ) ) )
250
238
}
251
- ) *
252
- }
253
-
254
- if is_pending {
255
- Pending
256
239
} else {
257
- Ready ( Ok ( ( $( {
258
- // Extract the future for this branch from the tuple.
259
- let ( $( $skip, ) * fut, .. ) = & mut futures;
260
-
261
- // Safety: future is stored on the stack above
262
- // and never moved.
263
- let mut fut = unsafe { Pin :: new_unchecked( fut) } ;
264
-
265
- fut
266
- . take_output( )
267
- . expect( "expected completed future" )
268
- . ok( )
269
- . expect( "expected Ok(_)" )
270
- } , ) * ) ) )
271
- }
272
- } ) . await ,
273
- // don't rotate the poll order so no skipping
274
- false => poll_fn( move |cx| {
275
- const COUNT : u32 = $( $total) * ;
276
- let mut is_pending = false ;
277
- let mut to_run = COUNT ;
278
-
279
- // no loop since we don't skip the first time through
280
- $(
281
- // Extract the future for this branch from the tuple.
282
- let ( $( $skip, ) * fut, .. ) = & mut * futures;
283
-
284
- // Safety: future is stored on the stack above
285
- // and never moved.
286
- let mut fut = unsafe { Pin :: new_unchecked( fut) } ;
287
-
288
- // Try polling
289
- if fut. as_mut( ) . poll( cx) . is_pending( ) {
290
- is_pending = true ;
291
- } else if fut. as_mut( ) . output_mut( ) . expect( "expected completed future" ) . is_err( ) {
292
- return Ready ( Err ( fut. take_output( ) . expect( "expected completed future" ) . err( ) . unwrap( ) ) )
240
+ // Future skipped, one less future to skip in the next iteration
241
+ skip -= 1 ;
293
242
}
294
243
) *
244
+ }
295
245
296
246
if is_pending {
297
247
Pending
@@ -312,22 +262,21 @@ doc! {macro_rules! try_join {
312
262
} , ) * ) ) )
313
263
}
314
264
} ) . await
315
- }
316
265
} } ;
317
266
318
267
// ===== Normalize =====
319
268
320
- ( @ { rotate_poll_order=$rotate_poll_order : literal ; ( $( $s: tt) * ) ( $( $n: tt) * ) $( $t: tt) * } $e: expr, $( $r: tt) * ) => {
321
- $crate :: try_join!( @{ rotate_poll_order=$rotate_poll_order ; ( $( $s) * _) ( $( $n) * + 1 ) $( $t) * ( $( $s) * ) $e, } $( $r) * )
269
+ ( @ { rotator=$rotator : ty ; ( $( $s: tt) * ) ( $( $n: tt) * ) $( $t: tt) * } $e: expr, $( $r: tt) * ) => {
270
+ $crate :: try_join!( @{ rotator=$rotator ; ( $( $s) * _) ( $( $n) * + 1 ) $( $t) * ( $( $s) * ) $e, } $( $r) * )
322
271
} ;
323
272
324
273
// ===== Entry point =====
325
274
( biased; $( $e: expr) , + $( , ) ?) => {
326
- $crate :: try_join!( @{ rotate_poll_order= false ; ( ) ( 0 ) } $( $e, ) * )
275
+ $crate :: try_join!( @{ rotator=$ crate :: macros :: support :: BiasedRotator ; ( ) ( 0 ) } $( $e, ) * )
327
276
} ;
328
277
329
278
( $( $e: expr) , + $( , ) ?) => {
330
- $crate :: try_join!( @{ rotate_poll_order= true ; ( ) ( 0 ) } $( $e, ) * )
279
+ $crate :: try_join!( @{ rotator=$ crate :: macros :: support :: Rotator < COUNT > ; ( ) ( 0 ) } $( $e, ) * )
331
280
} ;
332
281
333
282
( biased; ) => { async { Ok ( ( ) ) } . await } ;
0 commit comments