I remember that during the „old tokio-0.1 days“, to work effectively with streams and sinks, one should try to pack a lot into map(), then() etc. before wrapping things up with for_each() or packing it into a forward(). (I might be oversimplifying here.)
Has that situation changed? Is there a reason to still use stream.map(f).forward(sink) over something like while let Some(msg) = stream.next().await { […] sink.send(msg_f);} beyond functional vs imperative style and ergonomics?
I don't think there's any reason to use the combinators today. The only exception are the ones that help you execute several operations concurrently such as buffer_unordered.
You see a similar situation in JavaScript where it's possible to do the same operation using const y = some_promise.then(foo) and const x = await some_promise; const y = foo(x) syntax.
In some situations the then() syntax may be cleaner or more readable, whereas other situations may lend themselves to await.
At this point, I'd say it's mostly a stylistic choice although there are situations where one form is more desireable than the other (error propagation with future.await?, buffer_unordered, etc.).
That was the essence what I was curious about. So besides semantics, there is really no big advantage of using stream.forward(sink) anymore if one is not explicitly interested in concurrent stream-processing?
Alternative question - if I wanted to process a stream concurrently, how would I do that then? I guess with spawn() then? I’m trying to develop a feeling for performance implications of these patterns.