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,