How to specify generic trait bounds with associated types?


#1

i’m trying to write a function that takes a hyper service and hands it off to hyper’s Http::bind_connection, the problem is hyper’s Http::bind_connection has the following definition.

fn bind_connection<S, I, Bd>(
    &self, 
    handle: &Handle, 
    io: I, 
    remote_addr: SocketAddr, 
    service: S
) 
where
    S: Service<Request = Request, Response = Response<Bd>, Error = Error> + 'static,
    Bd: Stream<Item = B, Error = Error> + 'static,
    I: AsyncRead + AsyncWrite + 'static, 

and my function definition


fn serve<T>(service: T) -> io::Result<()>
where
    T: Service,
{

    let mut core = Core::new()?;
    let handle = core.handle();
    let addr = "0.0.0.0:8080".parse().unwrap();

    let listener = TcpListener::bind(&addr, &handle)?;

    let server = Http::new();

    core.run(listener.incoming().for_each(|(socket, peerAddr)| {
        server.bind_connection(&handle, socket, peerAddr, service);

        Ok(())
    }))?;



    Ok(())
}

the errors

error[E0271]: type mismatch resolving `<T as hyper::client::Service>::Request == hyper::Request`
  --> src/main.rs:30:16
   |
30 |         server.bind_connection(&handle, socket, peerAddr, service);
   |                ^^^^^^^^^^^^^^^ expected associated type, found struct `hyper::Request`
   |
   = note: expected type `<T as hyper::client::Service>::Request`
              found type `hyper::Request`

error[E0271]: type mismatch resolving `<T as hyper::client::Service>::Response == hyper::Response<_>`
  --> src/main.rs:30:16
   |
30 |         server.bind_connection(&handle, socket, peerAddr, service);
   |                ^^^^^^^^^^^^^^^ expected associated type, found struct `hyper::Response`
   |
   = note: expected type `<T as hyper::client::Service>::Response`
              found type `hyper::Response<_>`

error[E0271]: type mismatch resolving `<T as hyper::client::Service>::Error == hyper::Error`
  --> src/main.rs:30:16
   |
30 |         server.bind_connection(&handle, socket, peerAddr, service);
   |                ^^^^^^^^^^^^^^^ expected associated type, found enum `hyper::Error`
   |
   = note: expected type `<T as hyper::client::Service>::Error`
              found type `hyper::Error`

error: aborting due to 3 previous errors

error: Could not compile `playground`.

To learn more, run the command again with --verbose.

I know this has something to do with the associated types not being satisfied, but i honestly don’t know how to proceed, any help would be appreciated.

play.rust-lang link


#2

you can specify the types like this:

fn serve<T: 'static>(service: T) -> io::Result<()>
where
    T: Service<Request = hyper::Request, Response = hyper::Response, Error = hyper::Error>,
{

#3

wow, thanks a lot!


#4

Note that you’ll likely want to use https://docs.rs/hyper/0.11.2/hyper/server/struct.Http.html#method.bind instead, which takes a NewService instead of Service.

As you have it written, it won’t work because service will need to be shared across all incoming connections (because your have incoming().for_each(...)). So instead you’d want to pass a NewService, which is a factory of Service instances, and let hyper create them for each connection.

This isn’t related to your question directly, but just an FYI.