futures::stream::Fuse vs async_std::stream::Fuse

I'm trying to figure out which fuse method is called in the following code:

type MyReceiver<T> = futures::channel::mpsc::UnboundedReceiver<T>;
let mut f = m.fuse();

where m is a &mut MyReceiver<String>. From locally built documentation, I found that method fuse is provided by futures::stream::StreamExt trait, which is implemented by m. That method returns a futures::stream::Fuse<Self> so i tried to annotate type of f:

let mut f: futures::stream::Fuse<&mut MyReceiver<String>> = m.fuse();

Compiler complains with the error:

expected struct main::futures::stream::Fuse, found struct main::async_std::stream::Fuse. Maybe it's a real easy question but i think i'm missing something.

Thank you all

Async std also provides a StreamExt::fuse method.

Hi,

yes, but documentation lists, among implemented traits, futures::stream::StreamExt and not async_std::stream::SteamExt. I built documentation through cargo doc. I supposed that building documentation, the correct implemented traits were linked.

Which one did you import?

I'm trying to understand code at:

https://book.async.rs/tutorial/handling_disconnection.html#final-code

the imports are:

use async_std::{
    io::BufReader,
    net::{TcpListener, TcpStream, ToSocketAddrs},
    prelude::*,
    task,
};
use futures::channel::mpsc;
use futures::sink::SinkExt;
use futures::{select, FutureExt};
use std::{
    collections::hash_map::{Entry, HashMap},
    future::Future,
    sync::Arc,
};

Thanks

Both async_std::stream::StreamExt and futures::stream::StreamExt are implemented for all streams.

While cargo doc is great, I don't think it will link implementations from downstream crates back into the upstream documentation. Specifically, things in futures will only list implementations from futures and its dependencies, even if the documentation is built as part of a larger project.

Since async_std::stream::StreamExt is defined and implemented in async_std, and futures doesn't depend on async_std, it probably will never show up in futures documentation. However, if you look at async_std docs, there's an impl which covers all futures streams.


I believe the async_std::prelude::* import is bringing in async_std's StreamExt trait, and so .fuse() ends up being async_std::stream::StreamExt::fuse. You can see everything the prelude includes here.

If you want to use the futures one instead, you could remove that prelude import, and instead import from futures::prelude::*. You could also leave in both preludes, but I think that would run into problems since .fuse() would become ambiguous.

Hi,

thank you very much, i missed the blanket implementation you linked. So, just to recap, here we don't have an ambiguous call, which is resolved to async_std::stream::StreamExt::fuse, because a StreamExt blanket implementation is defined in async_std for all types that implement futures::stream::Stream and hence also for futures::channel::mpsc::UnboundedReceiver. Is this correct? Sorry but i'm pretty new to Rust.

Thanks

1 Like

Yeah that's why it resolves to that fuse. The reason its not ambiguous is because you didn't import futures' StreamExt trait.

1 Like

async_std reexports traits from futures. It just lies to the rustdoc to generate its own docs for those traits. Don't ask me why it does so.

While this is true for many traits, including Stream itself, I don't think it's true for StreamExt. There are definitely difference between futures and async_std - for instance, async_std::stream::StreamExt defines methods like any, all and cloned, which aren't present in futures::stream::StreamExt.

Looking at the source for async_std 1.5.0, too, it seems like they do define their own StreamExt separate from future's.

Hi,

yes, asyc_std::stream::StreamExt is not a re-exported traits. I think that async_std::stream::Stream is re-exported from futures::stream::Stream in order to define the blanket implementation for async_std::Stream::StreamExt linked by @daboross

async-std does not need to re-export the trait to make a blanket implementation. That can be done while referring to external traits. It is re-exported to make importing the trait easier.

Hi,

ah ok, you're right.

Thanks