Description
Hi there! So this is a really fun issue I spent some time debugging. I had written an adapter that sits on top of a Peekable<FuturesUnordered<T>>
. I had some code that did something like:
// self.stream is a Peekable<FuturesUnordered<T>>
match self.stream.poll_next(ctx) {
// do some stuff here
}
self.stream.get_mut().push(new_future);
self.stream.poll_peek(ctx);
I found that if the inner FuturesUnordered
dropped to having no futures from the first poll_next
, then poll_peek
always returns Poll::Ready(None)
after that.
This is because Peekable
uses the Fuse
adapter internally (source code link).
I worked around it by writing my own version of Peekable
that didn't use Fuse
internally. Note that FuturesUnordered
already implements FusedStream
so I didn't have to change anything about Peekable
.
Potential solutions
I discussed this issue with a couple of folks and here are some thoughts we had:
-
Easiest, non-breaking change: add a
reset_fuse
method to theFuse
adapter, as well as any other adapters that use aFuse
internally. That would let me useget_mut()
followed byreset_fuse()
to inform the adapter that it should start polling for values again. (There would also be an advocacy component here -- if you write an adapter that uses one that hasreset_fuse
internally, you must also expose areset_fuse
method.) -
Remove the
Fuse
adapter fromPeekable
and all other adapters that useFuse
, and replace it with internal logic. This makes a lot of logical sense to me, but it is a breaking change because it won't be possible to maintain theFusedStream for Peekable<St> where St: Stream
impl.However, it would still be possible to write
impl FusedStream for Peekable<St> where St: FusedStream
. Also, other people might build their own adapters that useFuse
anyway, so some other workaround likereset_fuse
is necessary for ecosystem cohesion. -
Add a
FusedStreamExt
trait and a whole new series of methodspeekable_fused
etc that work onFusedStream
s. This would solve the problem, sinceFuturesUnordered
implementsFusedStream
, but this seems excessive. -
Revisit the definition of
FusedStream
as a breaking change.FusedStream
really isn't likeFusedIterator
at all -- this was quite surprising to me and to other people I discussed the issue with. I'm not sure what the semantics would be but requiring workarounds likereset_fuse
feels like a little bit of a code smell.