146 lines
4.0 KiB
Rust
146 lines
4.0 KiB
Rust
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!()
|
|
}
|
|
}
|