futures::stream::StreamExt seems inconsistent about which callbacks are async and which are sync

I've been writing async code recently and I'm a bit puzzled by the design of futures::stream::StreamExt.

Most of the functions on this trait require asynchronous callbacks, e.g. filter, filter_map, take_while.

However map doesn't: it takes a synchronous callback... but it does have an async equivalent then.

I often don't need the async version of filter or filter_map. It's not a big deal to work around; I could either use an async block or std::future::ready, but it's mentally complex to remember which is which.

Is there a way and would it be a good idea to make these functions generic over both a sync and an async closure so that I don't have to think about this? If not, wouldn't it make sense to have two parallel sets of functions? for instance:

map, filter, take_while - synchronous closure
then, then_filter, then_take_while - closure returning a Future

1 Like

There is no current way for genericity. If you used tokio's StreamExt or async-std's StreamExt instead they’re all synchronous other than then, so you might want that.