diff options
Diffstat (limited to 'third_party/rust/hyper/src/common/exec.rs')
-rw-r--r-- | third_party/rust/hyper/src/common/exec.rs | 145 |
1 files changed, 145 insertions, 0 deletions
diff --git a/third_party/rust/hyper/src/common/exec.rs b/third_party/rust/hyper/src/common/exec.rs new file mode 100644 index 0000000000..76f616184b --- /dev/null +++ b/third_party/rust/hyper/src/common/exec.rs @@ -0,0 +1,145 @@ +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!() + } +} |