I have a library which uses hyper internally. I want the user to be able to create an App
which contains a Server
internally that handles HTTP connections.
use hyper::server::conn::AddrIncoming;
use hyper::server::Server;
use hyper::service::service_fn_ok;
use std::net::SocketAddr;
pub struct App {
inner: Server<AddrIncoming, ()>,
}
impl App {
pub fn new() -> Self {
let addr = SocketAddr::from(([0, 0, 0, 0], 3000));
let inner = Server::bind(&addr).serve(|| service_fn_ok(|_req| unimplemented!()));
App { inner }
}
}
(Playground link)
The error is, as expected:
error[E0308]: mismatched types
--> src/lib.rs:15:15
|
15 | App { inner }
| ^^^^^ expected (), found closure
|
= note: expected type `hyper::server::Server<_, ()>`
found type `hyper::server::Server<_, [closure@src/lib.rs:13:47: 13:88]>`
It's not well documented, but the second type parameter for Server
is the kind of MakeService
it uses.
I can't figure out how to refer to the closure in the type of inner
. Is there some way that I can box the closure to make the code compile? Is there a way to implement MakeService
by hand, instead of using a closure?
The hyper docs refer to the function make_service_fn
, which returns a MakeServiceFn
, but the type isn't public, so I can't use it in the type of inner
.
The problem is due to a type mismatch. In Rust, a type parameter is part of the type of a struct, so the type parameters for the server in your struct must match the ones you defined in your struct. In your case they don't.
There are 2 solutions to your problem.
pub struct App<T> {
inner: Server<AddrIncoming, T>,
}
Now you'll be able to create apps with different types for the second type parameter of the server
In your case, the type of the second argument is ``, so you would declare your struct like this:
type Service = ?; // This is really hard to find in this case.
pub struct App {
inner: Server<AddrIncoming, Service>,
}
In your case, I would recommend the first one because the type of the second type parameter of Server
is hard to find and could very well change during the development of your program, so it's much easier to just have a type parameter on your struct.
However, sometimes you won't be able to use certain method on your server if you don't know that its type parameters don't implement certain traits, so you can add these traits to your type parameter like this:
pub struct App<T: Service> {
inner: Server<AddrIncoming, T>,
}
It is recommended not to put the type parameters on the struct itself and to only put them on the impl
blocks:
pub struct App<T> {
inner: Server<AddrIncoming, T>,
}
impl App<T: Service> {
// Here you'll be able to use the method from Server where T has to be a Service.
}
You can also do the same for functions like this:
pub struct App<T> {
inner: Server<AddrIncoming, T>,
}
fn some_function(app: App<T: Service>) {
// Here you'll be able to use the method from Server where T has to be a Service
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With