feat(server): allow !Send Servers
				
					
				
			Until this commit, servers have required that `Service` and their `Future` to be `Send`, since the server needs to spawn some internal tasks to an executor, and by default, that is `tokio::spawn`, which could be spawning to a threadpool. This was true even if the user were certain there was no threadpool involved, and was instead using a different single-threaded runtime, like `tokio::runtime::current_thread`. This changes makes all the server pieces generic over an `E`, which is essentially `Executor<PrivateTypes<Server::Future>>`. There's a new set of internal traits, `H2Exec` and `NewSvcExec`, which allow for the type signature to only show the generics that the user is providing. The traits cannot be implemented explicitly, but there are blanket implementations for `E: Executor<SpecificType>`. If the user provides their own executor, it simply needs to have a generic `impl<F> Executor<F> for MyExec`. That impl can have bounds deciding whether to require `F: Send`. If the executor does require `Send`, and the `Service` futures are `!Send`, there will be compiler errors. To prevent a breaking change, all the types that gained the `E` generic have a default type set, which is the original `tokio::spawn` executor.
This commit is contained in:
		| @@ -5,7 +5,7 @@ use tokio_io::{AsyncRead, AsyncWrite}; | ||||
|  | ||||
| use ::headers::content_length_parse_all; | ||||
| use ::body::Payload; | ||||
| use ::common::Exec; | ||||
| use ::common::exec::H2Exec; | ||||
| use ::headers; | ||||
| use ::service::Service; | ||||
| use ::proto::Dispatched; | ||||
| @@ -13,12 +13,12 @@ use super::{PipeToSendStream, SendBuf}; | ||||
|  | ||||
| use ::{Body, Response}; | ||||
|  | ||||
| pub(crate) struct Server<T, S, B> | ||||
| pub(crate) struct Server<T, S, B, E> | ||||
| where | ||||
|     S: Service, | ||||
|     B: Payload, | ||||
| { | ||||
|     exec: Exec, | ||||
|     exec: E, | ||||
|     service: S, | ||||
|     state: State<T, B>, | ||||
| } | ||||
| @@ -40,15 +40,16 @@ where | ||||
| } | ||||
|  | ||||
|  | ||||
| impl<T, S, B> Server<T, S, B> | ||||
| impl<T, S, B, E> Server<T, S, B, E> | ||||
| where | ||||
|     T: AsyncRead + AsyncWrite, | ||||
|     S: Service<ReqBody=Body, ResBody=B>, | ||||
|     S::Error: Into<Box<::std::error::Error + Send + Sync>>, | ||||
|     S::Future: Send + 'static, | ||||
|     //S::Future: Send + 'static, | ||||
|     B: Payload, | ||||
|     E: H2Exec<S::Future, B>, | ||||
| { | ||||
|     pub(crate) fn new(io: T, service: S, exec: Exec) -> Server<T, S, B> { | ||||
|     pub(crate) fn new(io: T, service: S, exec: E) -> Server<T, S, B, E> { | ||||
|         let handshake = Builder::new() | ||||
|             .handshake(io); | ||||
|         Server { | ||||
| @@ -76,13 +77,14 @@ where | ||||
|     } | ||||
| } | ||||
|  | ||||
| impl<T, S, B> Future for Server<T, S, B> | ||||
| impl<T, S, B, E> Future for Server<T, S, B, E> | ||||
| where | ||||
|     T: AsyncRead + AsyncWrite, | ||||
|     S: Service<ReqBody=Body, ResBody=B>, | ||||
|     S::Error: Into<Box<::std::error::Error + Send + Sync>>, | ||||
|     S::Future: Send + 'static, | ||||
|     //S::Future: Send + 'static, | ||||
|     B: Payload, | ||||
|     E: H2Exec<S::Future, B>, | ||||
| { | ||||
|     type Item = Dispatched; | ||||
|     type Error = ::Error; | ||||
| @@ -116,14 +118,14 @@ where | ||||
|     T: AsyncRead + AsyncWrite, | ||||
|     B: Payload, | ||||
| { | ||||
|     fn poll_server<S>(&mut self, service: &mut S, exec: &Exec) -> Poll<(), ::Error> | ||||
|     fn poll_server<S, E>(&mut self, service: &mut S, exec: &E) -> Poll<(), ::Error> | ||||
|     where | ||||
|         S: Service< | ||||
|             ReqBody=Body, | ||||
|             ResBody=B, | ||||
|         >, | ||||
|         S::Error: Into<Box<::std::error::Error + Send + Sync>>, | ||||
|         S::Future: Send + 'static, | ||||
|         E: H2Exec<S::Future, B>, | ||||
|     { | ||||
|         while let Some((req, respond)) = try_ready!(self.conn.poll().map_err(::Error::new_h2)) { | ||||
|             trace!("incoming request"); | ||||
| @@ -132,7 +134,7 @@ where | ||||
|                 ::Body::h2(stream, content_length) | ||||
|             }); | ||||
|             let fut = H2Stream::new(service.call(req), respond); | ||||
|             exec.execute(fut)?; | ||||
|             exec.execute_h2stream(fut)?; | ||||
|         } | ||||
|  | ||||
|         // no more incoming streams... | ||||
| @@ -141,7 +143,8 @@ where | ||||
|     } | ||||
| } | ||||
|  | ||||
| struct H2Stream<F, B> | ||||
| #[allow(missing_debug_implementations)] | ||||
| pub struct H2Stream<F, B> | ||||
| where | ||||
|     B: Payload, | ||||
| { | ||||
|   | ||||
		Reference in New Issue
	
	Block a user