| use std::fmt; |
| use std::future::Future; |
| use std::pin::Pin; |
| use std::sync::Arc; |
| |
| #[cfg(all(feature = "server", any(feature = "http1", feature = "http2")))] |
| use crate::body::Body; |
| #[cfg(feature = "server")] |
| use crate::body::HttpBody; |
| #[cfg(all(feature = "http2", feature = "server"))] |
| use crate::proto::h2::server::H2Stream; |
| use crate::rt::Executor; |
| #[cfg(all(feature = "server", any(feature = "http1", feature = "http2")))] |
| use crate::server::server::{new_svc::NewSvcTask, Watcher}; |
| #[cfg(all(feature = "server", any(feature = "http1", feature = "http2")))] |
| use crate::service::HttpService; |
| |
| #[cfg(feature = "server")] |
| pub trait ConnStreamExec<F, B: HttpBody>: Clone { |
| fn execute_h2stream(&mut self, fut: H2Stream<F, B>); |
| } |
| |
| #[cfg(all(feature = "server", any(feature = "http1", feature = "http2")))] |
| pub trait NewSvcExec<I, N, S: HttpService<Body>, E, W: Watcher<I, S, E>>: Clone { |
| fn execute_new_svc(&mut self, fut: NewSvcTask<I, N, S, E, W>); |
| } |
| |
| pub(crate) type BoxSendFuture = Pin<Box<dyn Future<Output = ()> + Send>>; |
| |
| // Either the user provides an executor for background tasks, or we use |
| // `tokio::spawn`. |
| #[derive(Clone)] |
| pub enum Exec { |
| Default, |
| Executor(Arc<dyn Executor<BoxSendFuture> + Send + Sync>), |
| } |
| |
| // ===== impl Exec ===== |
| |
| impl Exec { |
| pub(crate) fn execute<F>(&self, fut: F) |
| where |
| F: Future<Output = ()> + Send + 'static, |
| { |
| match *self { |
| Exec::Default => { |
| #[cfg(feature = "tcp")] |
| { |
| tokio::task::spawn(fut); |
| } |
| #[cfg(not(feature = "tcp"))] |
| { |
| // If no runtime, we need an executor! |
| panic!("executor must be set") |
| } |
| } |
| Exec::Executor(ref e) => { |
| e.execute(Box::pin(fut)); |
| } |
| } |
| } |
| } |
| |
| impl fmt::Debug for Exec { |
| fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { |
| f.debug_struct("Exec").finish() |
| } |
| } |
| |
| #[cfg(feature = "server")] |
| impl<F, B> ConnStreamExec<F, B> for Exec |
| where |
| H2Stream<F, B>: Future<Output = ()> + Send + 'static, |
| B: HttpBody, |
| { |
| fn execute_h2stream(&mut self, fut: H2Stream<F, B>) { |
| self.execute(fut) |
| } |
| } |
| |
| #[cfg(all(feature = "server", any(feature = "http1", feature = "http2")))] |
| impl<I, N, S, E, W> NewSvcExec<I, N, S, E, W> for Exec |
| where |
| NewSvcTask<I, N, S, E, W>: Future<Output = ()> + Send + 'static, |
| S: HttpService<Body>, |
| W: Watcher<I, S, E>, |
| { |
| fn execute_new_svc(&mut self, fut: NewSvcTask<I, N, S, E, W>) { |
| self.execute(fut) |
| } |
| } |
| |
| // ==== impl Executor ===== |
| |
| #[cfg(feature = "server")] |
| impl<E, F, B> ConnStreamExec<F, B> for E |
| where |
| E: Executor<H2Stream<F, B>> + Clone, |
| H2Stream<F, B>: Future<Output = ()>, |
| B: HttpBody, |
| { |
| fn execute_h2stream(&mut self, fut: H2Stream<F, B>) { |
| self.execute(fut) |
| } |
| } |
| |
| #[cfg(all(feature = "server", any(feature = "http1", feature = "http2")))] |
| impl<I, N, S, E, W> NewSvcExec<I, N, S, E, W> for E |
| where |
| E: Executor<NewSvcTask<I, N, S, E, W>> + Clone, |
| NewSvcTask<I, N, S, E, W>: Future<Output = ()>, |
| S: HttpService<Body>, |
| W: Watcher<I, S, E>, |
| { |
| fn execute_new_svc(&mut self, fut: NewSvcTask<I, N, S, E, W>) { |
| self.execute(fut) |
| } |
| } |
| |
| // If http2 is not enable, we just have a stub here, so that the trait bounds |
| // that *would* have been needed are still checked. Why? |
| // |
| // Because enabling `http2` shouldn't suddenly add new trait bounds that cause |
| // a compilation error. |
| #[cfg(not(feature = "http2"))] |
| #[allow(missing_debug_implementations)] |
| pub struct H2Stream<F, B>(std::marker::PhantomData<(F, B)>); |
| |
| #[cfg(not(feature = "http2"))] |
| impl<F, B, E> Future for H2Stream<F, B> |
| where |
| F: Future<Output = Result<http::Response<B>, E>>, |
| B: crate::body::HttpBody, |
| B::Error: Into<Box<dyn std::error::Error + Send + Sync>>, |
| E: Into<Box<dyn std::error::Error + Send + Sync>>, |
| { |
| type Output = (); |
| |
| fn poll( |
| self: Pin<&mut Self>, |
| _cx: &mut std::task::Context<'_>, |
| ) -> std::task::Poll<Self::Output> { |
| unreachable!() |
| } |
| } |