How do I write a generic function that executes a hyper service?

I have two similar functions which run an HTTP server. run_http_server1() compiles without errors, but run_http_server2() has a generic specification which I cannot declare correctly and so I get compilation errors.

How do I declare the second function? Why does my declaration not work?

#[tokio::main]
async fn main() {
    // run_http_server1().await;
    run_http_server2::<MyService>().await;
}

async fn run_http_server1() {
    let addr = std::net::SocketAddr::from(([127, 0, 0, 1], 3333));

    let make_service = hyper::service::make_service_fn(|_conn| async {
        let svc = MyService::new("hello, world!".to_string());
        Ok::<_, std::convert::Infallible>(svc)
    });

    let server = hyper::Server::bind(&addr).serve(make_service);
    server.await.expect("server failed");
}

async fn run_http_server2<S>()
where
    S: tower::Service<hyper::Request<hyper::Body>> + 'static + Send + Factory,
    <S as tower::Service<hyper::Request<hyper::Body>>>::Error: Sync + Send + std::error::Error,
    <S as tower::Service<hyper::Request<hyper::Body>>>::Future: std::marker::Send,
{
    let addr = std::net::SocketAddr::from(([127, 0, 0, 1], 3333));

    let make_service = hyper::service::make_service_fn(|_conn| async {
        let svc = S::new("hello, world!".to_string());
        Ok::<_, std::convert::Infallible>(svc)
    });

    let server = hyper::Server::bind(&addr).serve(make_service);
    server.await.expect("server failed");
}

#[derive(Clone)]
struct MyService {
    s: String,
}

trait Factory {
    fn new(s: String) -> Self;
}

impl Factory for MyService {
    fn new(s: String) -> MyService {
        MyService { s }
    }
}

impl tower::Service<hyper::Request<hyper::Body>> for MyService {
    type Response = hyper::Response<hyper::Body>;
    type Error = std::convert::Infallible;
    type Future = futures::future::Ready<Result<Self::Response, Self::Error>>;

    fn poll_ready(
        &mut self,
        _cx: &mut std::task::Context<'_>,
    ) -> std::task::Poll<Result<(), Self::Error>> {
        std::task::Poll::Ready(Ok(()))
    }

    fn call(&mut self, _req: hyper::Request<hyper::Body>) -> Self::Future {
        let resp = hyper::Response::new(hyper::Body::from(self.s.clone()));
        futures::future::ready(Ok(resp))
    }
}

Here are my dependencies from Cargo.toml:

[dependencies]
hyper = { version = "0.14", features = ["full"] }
rustls-pemfile = "0.3"
tokio = { version = "1", features = ["full"] }
tokio-rustls = "0.23"
tower = { version = "0.4", features = ["make"] }
tracing = "0.1"
tracing-subscriber = { version="0.3", features = ["env-filter"] }
futures-util = "0.3"
futures = "0.3"
rustls = "0.20"

The error

 Compiling trial v0.1.0 (/home/alek/projects/rust/trial)
error[E0271]: type mismatch resolving `<<S as Service<Request<Body>>>::Future as futures::Future>::Output == Result<Response<_>, _>`
  --> src/main.rs:32:45
   |
32 |     let server = hyper::Server::bind(&addr).serve(make_service);
   |                                             ^^^^^ expected associated type, found struct `Response`
   |
   = note: expected enum `Result<<S as Service<Request<Body>>>::Response, <S as Service<Request<Body>>>::Error>`
              found enum `Result<Response<_>, _>`
   = help: consider constraining the associated type `<S as Service<Request<Body>>>::Response` to `Response<_>`
   = note: for more information, visit https://doc.rust-lang.org/book/ch19-03-advanced-traits.html
   = note: required because of the requirements on the impl of `futures::Future` for `hyper::proto::h2::server::H2Stream<<S as Service<Request<Body>>>::Future, _>`
   = note: required because of the requirements on the impl of `hyper::common::exec::ConnStreamExec<<S as Service<Request<Body>>>::Future, _>` for `hyper::common::exec::Exec`

error[E0271]: type mismatch resolving `<S as Service<Request<Body>>>::Response == Response<_>`
  --> src/main.rs:32:45
   |
32 |     let server = hyper::Server::bind(&addr).serve(make_service);
   |                                             ^^^^^ expected associated type, found struct `Response`
   |
   = note: expected associated type `<S as Service<Request<Body>>>::Response`
                       found struct `Response<_>`
   = help: consider constraining the associated type `<S as Service<Request<Body>>>::Response` to `Response<_>`
   = note: for more information, visit https://doc.rust-lang.org/book/ch19-03-advanced-traits.html
   = note: required because of the requirements on the impl of `hyper::service::http::HttpService<Body>` for `S`

error[E0277]: the trait bound `hyper::common::exec::Exec: hyper::common::exec::ConnStreamExec<<S as Service<Request<Body>>>::Future, _>` is not satisfied
  --> src/main.rs:33:5
   |
33 |     server.await.expect("server failed");
   |     ^^^^^^^^^^^^ the trait `hyper::common::exec::ConnStreamExec<<S as Service<Request<Body>>>::Future, _>` is not implemented for `hyper::common::exec::Exec`
   |
   = help: the following implementations were found:
             <hyper::common::exec::Exec as hyper::common::exec::ConnStreamExec<F, B>>
   = note: required because of the requirements on the impl of `futures::Future` for `hyper::server::conn::spawn_all::NewSvcTask<AddrStream, impl futures::Future, S, hyper::common::exec::Exec, hyper::server::conn::spawn_all::NoopWatcher>`
   = note: required because of the requirements on the impl of `hyper::common::exec::NewSvcExec<AddrStream, impl futures::Future, S, hyper::common::exec::Exec, hyper::server::conn::spawn_all::NoopWatcher>` for `hyper::common::exec::Exec`
   = note: 1 redundant requirements hidden
   = note: required because of the requirements on the impl of `futures::Future` for `Server<AddrIncoming, hyper::service::make::MakeServiceFn<[closure@src/main.rs:27:56: 30:6]>>`
note: required by `futures::Future::poll`
  --> /home/alek/.rustup/toolchains/stable-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/library/core/src/future/future.rs:99:5
   |
99 |     fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output>;
   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

error[E0271]: type mismatch resolving `<S as Service<Request<Body>>>::Response == Response<_>`
  --> src/main.rs:33:5
   |
33 |     server.await.expect("server failed");
   |     ^^^^^^^^^^^^ expected struct `Response`, found associated type
   |
   = note:       expected struct `Response<_>`
           found associated type `<S as Service<Request<Body>>>::Response`
   = help: consider constraining the associated type `<S as Service<Request<Body>>>::Response` to `Response<_>`
   = note: for more information, visit https://doc.rust-lang.org/book/ch19-03-advanced-traits.html
   = note: required because of the requirements on the impl of `hyper::service::http::HttpService<Body>` for `S`
   = note: required because of the requirements on the impl of `hyper::common::exec::NewSvcExec<AddrStream, impl futures::Future, S, hyper::common::exec::Exec, hyper::server::conn::spawn_all::NoopWatcher>` for `hyper::common::exec::Exec`
   = note: required because of the requirements on the impl of `futures::Future` for `Server<AddrIncoming, hyper::service::make::MakeServiceFn<[closure@src/main.rs:27:56: 30:6]>>`
note: required by `futures::Future::poll`
  --> /home/alek/.rustup/toolchains/stable-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/library/core/src/future/future.rs:99:5
   |
99 |     fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output>;
   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

error[E0271]: type mismatch resolving `<<S as Service<Request<Body>>>::Future as futures::Future>::Output == Result<Response<_>, _>`
  --> src/main.rs:33:5
   |
33 |     server.await.expect("server failed");
   |     ^^^^^^^^^^^^ expected struct `Response`, found associated type
   |
   = note: expected enum `Result<Response<_>, _>`
              found enum `Result<<S as Service<Request<Body>>>::Response, <S as Service<Request<Body>>>::Error>`
   = help: consider constraining the associated type `<S as Service<Request<Body>>>::Response` to `Response<_>`
   = note: for more information, visit https://doc.rust-lang.org/book/ch19-03-advanced-traits.html
   = note: required because of the requirements on the impl of `futures::Future` for `hyper::proto::h2::server::H2Stream<<S as Service<Request<Body>>>::Future, _>`
   = note: required because of the requirements on the impl of `hyper::common::exec::ConnStreamExec<<S as Service<Request<Body>>>::Future, _>` for `hyper::common::exec::Exec`
   = note: 1 redundant requirements hidden
   = note: required because of the requirements on the impl of `futures::Future` for `Server<AddrIncoming, hyper::service::make::MakeServiceFn<[closure@src/main.rs:27:56: 30:6]>>`
note: required by `futures::Future::poll`
  --> /home/alek/.rustup/toolchains/stable-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/library/core/src/future/future.rs:99:5
   |
99 |     fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output>;
   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

Some errors have detailed explanations: E0271, E0277.
For more information about an error, try `rustc --explain E0271`.
error: could not compile `trial` due to 5 previous errors

This is the key part of the error message. Adding the Response associated type to the Service constraint allows it to compile:

async fn run_http_server2<S>()
where
    S: tower::Service<hyper::Request<hyper::Body>, Response = hyper::Response<hyper::Body>>
        + 'static
        + Send
        + Factory,

Thank you so much!

This topic was automatically closed 90 days after the last reply. We invite you to open a new topic if you have further questions or comments.