use std::fmt; use std::sync::Arc; use futures::future::{Executor, Future}; use body::Payload; use proto::h2::server::H2Stream; use server::conn::spawn_all::{NewSvcTask, Watcher}; use service::Service; pub trait H2Exec: Clone { fn execute_h2stream(&self, fut: H2Stream) -> ::Result<()>; } pub trait NewSvcExec>: Clone { fn execute_new_svc(&self, fut: NewSvcTask) -> ::Result<()>; } // Either the user provides an executor for background tasks, or we use // `tokio::spawn`. #[derive(Clone)] pub enum Exec { Default, Executor(Arc + Send>> + Send + Sync>), } // ===== impl Exec ===== impl Exec { pub(crate) fn execute(&self, fut: F) -> ::Result<()> where F: Future + Send + 'static, { match *self { Exec::Default => { #[cfg(feature = "runtime")] { use std::error::Error as StdError; use ::tokio_executor::Executor; 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::new(fut)) .map_err(|err| { warn!("executor error: {:?}", err); ::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.execute(Box::new(fut)) .map_err(|err| { warn!("executor error: {:?}", err.kind()); ::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(&self, fut: H2Stream) -> ::Result<()> { self.execute(fut) } } impl NewSvcExec for Exec where NewSvcTask: Future + Send + 'static, S: Service, W: Watcher, { fn execute_new_svc(&self, fut: NewSvcTask) -> ::Result<()> { self.execute(fut) } } // ==== impl Executor ===== impl H2Exec for E where E: Executor> + Clone, H2Stream: Future, B: Payload, { fn execute_h2stream(&self, fut: H2Stream) -> ::Result<()> { self.execute(fut) .map_err(|err| { warn!("executor error: {:?}", err.kind()); ::Error::new_execute("custom executor failed") }) } } impl NewSvcExec for E where E: Executor> + Clone, NewSvcTask: Future, S: Service, W: Watcher, { fn execute_new_svc(&self, fut: NewSvcTask) -> ::Result<()> { self.execute(fut) .map_err(|err| { warn!("executor error: {:?}", err.kind()); ::Error::new_execute("custom executor failed") }) } } // ===== StdError impls =====