rusttraitsopaque-types

How to refer to type of impl output in Rust?


I'm trying to implement a stream in Rust for use in a tonic GRPC handler and encountered this difficulty: most ways of creating streams don't have easily-expressible types, yet the GRPC trait I need to implement requires a specific Stream type. Something like this (simplified):

// trait to implement
trait GrpcHandler {
  type RespStream: futures::Stream<ResponseType> + Send + 'static
  fn get_resp_stream() -> Self::RespStream;
}

// a start at implementing it
impl GrpcHandler for MyHandler {
  type RespStream = ???; // what do I put here?
  fn get_resp_stream() -> Self::RespStream {
    futures::stream::unfold((), |_| async {
      tokio::time::sleep(tokio::time::Duration::from_secs(1)).await;
      Some((ResponseType {}, ()))
    })
  }
}

I know the type of my stream is technically something like Unfold<(), ComplicatedFnSignatureWithImpl, ComplicatedFutureSignatureWithImpl>, but even if I typed that whole thing in, the compiler wouldn't be happy about it being an opaque type. How can I refer to the type of this stream?


Solution

  • Unfortunately there is no good way in stable Rust to do that without dynamic dispatch. You have to use dyn Stream, and futures provides BoxStream for that:

    impl GrpcHandler for MyHandler {
        type RespStream = futures::stream::BoxStream<'static, ResponseType>;
        fn get_resp_stream() -> Self::RespStream {
            futures::stream::unfold((), |_| async {
                tokio::time::sleep(tokio::time::Duration::from_secs(1)).await;
                Some((ResponseType {}, ()))
            })
            .boxed()
        }
    }
    

    If you use nightly, you can use the unstable type_alias_impl_trait feature to avoid the overhead of dynamic dispatch:

    #![feature(type_alias_impl_trait)]
    
    impl GrpcHandler for MyHandler {
        type RespStream = impl futures::Stream<Item = ResponseType> + Send + 'static;
        fn get_resp_stream() -> Self::RespStream {
            futures::stream::unfold((), |_| async {
                tokio::time::sleep(tokio::time::Duration::from_secs(1)).await;
                Some((ResponseType {}, ()))
            })
        }
    }