diff --git a/src/either.rs b/src/either.rs new file mode 100644 index 00000000..efc6b3d5 --- /dev/null +++ b/src/either.rs @@ -0,0 +1,103 @@ +//! Contains `Either` service and related types and functions. +use futures::{future, Async, Future, Poll}; + +use super::service::{NewService, Service}; + +/// Combine two different service types into a single type. +/// +/// Both services must be of the same request, response, and error types. +/// `EitherService` is useful for handling conditional branching in service +/// middleware to different inner service types. +pub enum EitherService { + A(A), + B(B), +} + +impl Service for EitherService +where + A: Service, + B: Service, +{ + type Request = A::Request; + type Response = A::Response; + type Error = A::Error; + type Future = future::Either; + + fn poll_ready(&mut self) -> Poll<(), Self::Error> { + match self { + EitherService::A(ref mut inner) => inner.poll_ready(), + EitherService::B(ref mut inner) => inner.poll_ready(), + } + } + + fn call(&mut self, req: Self::Request) -> Self::Future { + match self { + EitherService::A(ref mut inner) => future::Either::A(inner.call(req)), + EitherService::B(ref mut inner) => future::Either::B(inner.call(req)), + } + } +} + +/// Combine two different new service types into a single type. +pub enum Either { + A(A), + B(B), +} + +impl NewService for Either +where + A: NewService, + B: NewService< + Request = A::Request, + Response = A::Response, + Error = A::Error, + InitError = A::InitError, + >, +{ + type Request = A::Request; + type Response = A::Response; + type Error = A::Error; + type InitError = A::InitError; + type Service = EitherService; + type Future = EitherNewService; + + fn new_service(&self) -> Self::Future { + match self { + Either::A(ref inner) => EitherNewService::A(inner.new_service()), + Either::B(ref inner) => EitherNewService::B(inner.new_service()), + } + } +} + +#[doc(hidden)] +pub enum EitherNewService { + A(A::Future), + B(B::Future), +} + +impl Future for EitherNewService +where + A: NewService, + B: NewService< + Request = A::Request, + Response = A::Response, + Error = A::Error, + InitError = A::InitError, + >, +{ + type Item = EitherService; + type Error = A::InitError; + + fn poll(&mut self) -> Poll { + match self { + EitherNewService::A(ref mut fut) => { + let service = try_ready!(fut.poll()); + Ok(Async::Ready(EitherService::A(service))) + } + EitherNewService::B(ref mut fut) => { + let service = try_ready!(fut.poll()); + Ok(Async::Ready(EitherService::B(service))) + } + } + } +} diff --git a/src/lib.rs b/src/lib.rs index a1204730..f6262791 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -58,6 +58,7 @@ extern crate webpki_roots; pub mod cloneable; pub mod connector; pub mod counter; +pub mod either; pub mod framed; pub mod inflight; pub mod keepalive; diff --git a/src/server/services.rs b/src/server/services.rs index a2dad1ba..43ba8ce0 100644 --- a/src/server/services.rs +++ b/src/server/services.rs @@ -12,8 +12,11 @@ use service::{NewService, Service}; /// Server message pub enum ServerMessage { + /// New stream Connect(net::TcpStream), + /// Gracefull shutdown Shutdown(Duration), + /// Force shutdown ForceShutdown, } @@ -220,6 +223,18 @@ impl InternalServiceFactory for Box { } } +impl ServiceFactory for F +where + F: Fn() -> T + Send + Clone + 'static, + T: NewService, +{ + type NewService = T; + + fn create(&self) -> T { + (self)() + } +} + impl StreamServiceFactory for F where F: Fn() -> T + Send + Clone + 'static,