Repository: tokio-rs/tokio
File: tokio/src/macros/try_join.rs (Rust)

Code before:
        // Safety: nothing must be moved out of `futures`. This is to satisfy
        // the requirement of `Pin::new_unchecked` called below.
        //
        // We can't use the `pin!` macro for this because `futures` is a tuple
        // and the standard library provides no way to pin-project to the fields
        // of a tuple.
        let mut futures = ( $( maybe_done($e), )* );

        // This assignment makes sure that the `poll_fn` closure only has a
        // reference to the futures, instead of taking ownership of them. This
        // mitigates the issue described in
        // <https://internals.rust-lang.org/t/surprising-soundness-trouble-around-pollfn/17484>
        let mut futures = &mut futures;

        // Each time the future created by poll_fn is polled,
        // if not running in biased mode,
        // a different future will be polled first
        // to ensure every future passed to join! gets a chance to make progress even if
        // one of the futures consumes the whole budget.
        //
        // This is number of futures that will be skipped in the first loop
        // iteration the next time.
        //
        // If running in biased mode, this value will always be 0.
        let mut skip_next_time: u32 = 0;
        let rotate_skip = $rotate_poll_order;

        poll_fn(move |cx| {
            const COUNT: u32 = $($total)*;

            let mut is_pending = false;

            let mut to_run = COUNT;

            // The number of futures that will be skipped in the first loop iteration
            let mut skip = skip_next_time;

            // only change skip index if we are not in biased mode, aka rotate_poll_order == true
            if rotate_skip {
                skip_next_time = if skip + 1 == COUNT { 0 } else { skip + 1 };
            }

            // This loop runs twice and the first `skip` futures
            // are not polled in the first iteration.
            loop {
            $(
                if skip == 0 {
                    if to_run == 0 {
                        // Every future has been polled
                        break;
                    }

Review comment (performance):
I would like to avoid having this variable at all when using biased. I don't think it can be optimized out because it gets stored as a field in the closure type.

Code after:
        // Safety: nothing must be moved out of `futures`. This is to satisfy
        // the requirement of `Pin::new_unchecked` called below.
        //
        // We can't use the `pin!` macro for this because `futures` is a tuple
        // and the standard library provides no way to pin-project to the fields
        // of a tuple.
        let mut futures = ( $( maybe_done($e), )* );

        // This assignment makes sure that the `poll_fn` closure only has a
        // reference to the futures, instead of taking ownership of them. This
        // mitigates the issue described in
        // <https://internals.rust-lang.org/t/surprising-soundness-trouble-around-pollfn/17484>
        let mut futures = &mut futures;

        const COUNT: u32 = $($total)*;

        // Each time the future created by poll_fn is polled, if not using biased mode,
        // a different future is polled first to ensure every future passed to try_join!
        // can make progress even if one of the futures consumes the whole budget.
        let mut rotator = <$rotator>::default();

        poll_fn(move |cx| {
            let mut is_pending = false;
            let mut to_run = COUNT;

            // The number of futures that will be skipped in the first loop iteration.
            let mut skip = rotator.num_skip();

            // This loop runs twice and the first `skip` futures
            // are not polled in the first iteration.
            loop {
            $(
                if skip == 0 {
                    if to_run == 0 {
                        // Every future has been polled
                        break;
                    }
                    to_run -= 1;

                    // Extract the future for this branch from the tuple.
                    let ( $($skip,)* fut, .. ) = &mut *futures;

                    // Safety: future is stored on the stack above
                    // and never moved.
                    let mut fut = unsafe { Pin::new_unchecked(fut) };

                    // Try polling
                    if fut.as_mut().poll(cx).is_pending() {
                        is_pending = true;
                    } else if fut.as_mut().output_mut().expect("expected completed future").is_err() {
                        return Ready(Err(fut.take_output().expect("expected completed future").err().unwrap()))