use std::fmt; use std::future::Future; use std::pin::Pin; use std::sync::Arc; use tokio_executor::{SpawnError, TypedExecutor}; use crate::body::{Payload, Body}; use crate::proto::h2::server::H2Stream; use crate::server::conn::spawn_all::{NewSvcTask, Watcher}; use crate::service::Service; pub trait H2Exec: Clone { fn execute_h2stream(&mut self, fut: H2Stream) -> crate::Result<()>; } pub trait NewSvcExec, E, W: Watcher>: Clone { fn execute_new_svc(&mut self, fut: NewSvcTask) -> crate::Result<()>; } type BoxFuture = Pin + Send>>; pub trait SharedExecutor { fn shared_spawn(&self, future: BoxFuture) -> Result<(), SpawnError>; } impl SharedExecutor for E where for<'a> &'a E: tokio_executor::Executor, { fn shared_spawn(mut self: &Self, future: BoxFuture) -> Result<(), SpawnError> { tokio_executor::Executor::spawn(&mut self, future) } } // Either the user provides an executor for background tasks, or we use // `tokio::spawn`. #[derive(Clone)] pub enum Exec { Default, Executor(Arc), } // ===== impl Exec ===== impl Exec { pub(crate) fn execute(&self, fut: F) -> crate::Result<()> where F: Future + Send + 'static, { match *self { Exec::Default => { #[cfg(feature = "runtime")] { use std::error::Error as StdError; struct TokioSpawnError; impl fmt::Debug for TokioSpawnError { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { fmt::Debug::fmt("tokio::spawn failed (is a tokio runtime running this future?)", f) } } impl fmt::Display for TokioSpawnError { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { fmt::Display::fmt("tokio::spawn failed (is a tokio runtime running this future?)", f) } } impl StdError for TokioSpawnError { fn description(&self) -> &str { "tokio::spawn failed" } } ::tokio_executor::DefaultExecutor::current() .spawn(Box::pin(fut)) .map_err(|err| { warn!("executor error: {:?}", err); crate::Error::new_execute(TokioSpawnError) }) } #[cfg(not(feature = "runtime"))] { // If no runtime, we need an executor! panic!("executor must be set") } }, Exec::Executor(ref e) => { e.shared_spawn(Box::pin(fut)) .map_err(|err| { warn!("executor error: {:?}", err); crate::Error::new_execute("custom executor failed") }) }, } } } impl fmt::Debug for Exec { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.debug_struct("Exec") .finish() } } impl H2Exec for Exec where H2Stream: Future + Send + 'static, B: Payload, { fn execute_h2stream(&mut self, fut: H2Stream) -> crate::Result<()> { self.execute(fut) } } impl NewSvcExec for Exec where NewSvcTask: Future + Send + 'static, S: Service, W: Watcher, { fn execute_new_svc(&mut self, fut: NewSvcTask) -> crate::Result<()> { self.execute(fut) } } // ==== impl Executor ===== impl H2Exec for E where E: TypedExecutor> + Clone, H2Stream: Future, B: Payload, { fn execute_h2stream(&mut self, fut: H2Stream) -> crate::Result<()> { self.spawn(fut) .map_err(|err| { warn!("executor error: {:?}", err); crate::Error::new_execute("custom executor failed") }) } } impl NewSvcExec for E where E: TypedExecutor> + Clone, NewSvcTask: Future, S: Service, W: Watcher, { fn execute_new_svc(&mut self, fut: NewSvcTask) -> crate::Result<()> { self.spawn(fut) .map_err(|err| { warn!("executor error: {:?}", err); crate::Error::new_execute("custom executor failed") }) } } // ===== StdError impls =====