rustrust-tonic

How to map a `Stream<Item=A>` into a `Stream<Item=B>`?


I'm using tonic and tonic returns a Streaming<A>, I want to turn it into a Box<dyn Stream<Item=B>>, so the user of my function don't need to know about tonic detail.

I tried

stream.map(|val| (turns A into B))

which gives me a Map<Streaming<A>, |A| -> B>, rather than a Stream<B> that I want.


Solution

  • Stream<Item = B> is a trait, not a type, so no value can be one. However, Map<Streaming<A>, |A| -> B> does implement Stream<Item = B>, which means it can be coerced into dyn Stream<Item = B>, which is a type. This trait object is put behind a pointer type (Box in this case) because it is unsized.

    let new_stream = stream.map(|val| b(val));
    Box::new(new_stream) as Box<dyn Stream<Item = B>>
    

    It's likely you can leave off the as cast, since type inference will pick it up in most cases.

    It may be possible to return impl Stream<Item = B> instead, which allows you to remove the Box. This hides the inner type from your public API.

    Also note that TryStream and TryStreamExt are useful for streams that return Result (they can be difficult to discover on your own). You should still return impl Stream or dyn Stream since those can be used as TryStream, but TryStream can't always be used as Stream. But you can use their methods inside your implementation.