Skip to content

FusedFuture and FusedStream #1219

Closed
Closed
@cramertj

Description

@cramertj

The select macro would be far more useful if it was usable inside of loops, like this:

pin_mut!(future_1, future_2, my_stream);
let mut state = ...;
loop {
    let x = select! {
        future_1 => { ...transform state... }
        future_2 => { ...transform state... }
        next(my_stream) as elem => { ... transform state... }
        done => { ... }
    };
    ...some more code doing something with x and state...
}

However, the Stream and Future traits require that they are not polled after completion, and they provide no way to check if completion has already occurred. It's possible to track this extra bit of state in a boolean or something as part of the macro, but then the looping functionality has to be built into the macro, meaning that (1) there would have to be separate select! and select_loop! macros and (2) any shared code or controlflow in the "always" branch would have to be duplicated across branches:

pin_mut!(future_1, future_2, my_stream);
let mut state = ...;
select_loop! {
    future_1 => { let x = ...transform state...; ...some more code doing something with x and state... }
    future_2 => { let x = ...transform state...; ...some more code doing something with x and state... }
    next(my_stream) as elem => { let x = ...transform state...; ...some more code doing something with x and state... }
    done => { let x = ...transform state...; ...some more code doing something with x and state... }
}

Another option would be to add FusedFuture and FusedStream with has_completed() methods, implement FusedFuture and FusedStream for many of the combinators which support them (in particular the fuse() combinator). This is likely more ergonomic for users familiar with how the system works, but could be confusing for new users who now have one more thing to understand (fusing, pinning, etc...).

Yet another option would be to require that all futures track this bit of state and add a has_completed method to the Future and Stream traits. This requires less involvement from end-users, but again increases the already-high ergonomic burden on manual-futures implementors.

Personally, I lean towards the FusedFuture/FusedStream approach as it adds minimal complexity for users who don't care about the select! combinator while still retaining the manual control-flow flexibility of select! + loop rather than select_loop!. However, I'm by no means attached to this idea, and I recognize that it pushes another point of complexity onto end users, which is disappointing. I'd like to hear what y'all think.

cc @seanmonstar @carllerche @withoutboats @aturon @Nemo157 @MajorBreakfast @cavedweller @tkilbourn @smklein

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions