For async streams, what does .fuse() do?


  1. I'm playing with async_tungstenite websocket stream.

  2. I do

future::select! {
  x = => { ... }
  1. I get compiler error about something not Fused.

  2. I do a let websocket_stream = websocket_stream.fuse()

  3. Things compile now.


Question: what does 'fuse' do? Why does futures::select! need it? What are the disadvantages of fuse (i.e. why isn't everything fused by default) ?

1 Like

Since the select! macro is designed to await multiple futures/streams in a loop even as some become exhausted, it needs some way to keep track of which futures/streams have already been exhausted so it doesn't await them again. fuse() is one way to do that; it ensures that once a stream is exhausted, it will always be exhausted when polled again. Some futures/streams may already inherently provide this property, so as an optimization, they may implement the FusedStream marker trait manually so that fuse() doesn't have to be used redundantly. On top of that, futures/streams which are polled after exhaustion are allowed to panic or exhibit weird behavior, and fuse() prevents that from happening.


It's basically Iterator::fuse() but for async.


Normally once you call next() on the stream and get a None, you aren't guaranteed that calling .next() again keeps giving you None. Instead, there are some streams that will panic instead if you use them after they have been exhausted. The .fuse() combinator wraps the stream and makes sure that any calls to .next() after the first None will return None again immediately instead of being forwarded to the inner stream.

The futures::select! macro tries to avoid the panics I mentioned by requiring that anything you are selecting over is fused. This is mostly relevant when things are used repeatedly in a loop.

You can find a lot more details in this issue and this PR.


This topic was automatically closed 90 days after the last reply. We invite you to open a new topic if you have further questions or comments.