1 //! Contains `Either` and related types and functions.
2 //!
3 //! See `Either` documentation for more details.
4 
5 use futures_core::ready;
6 use pin_project::{pin_project, project};
7 use std::{
8     future::Future,
9     pin::Pin,
10     task::{Context, Poll},
11 };
12 use tower_service::Service;
13 
14 /// Combine two different service types into a single type.
15 ///
16 /// Both services must be of the same request, response, and error types.
17 /// `Either` is useful for handling conditional branching in service middleware
18 /// to different inner service types.
19 #[pin_project]
20 #[derive(Clone, Debug)]
21 pub enum Either<A, B> {
22     /// One type of backing `Service`.
23     A(#[pin] A),
24     /// The other type of backing `Service`.
25     B(#[pin] B),
26 }
27 
28 type Error = Box<dyn std::error::Error + Send + Sync>;
29 
30 impl<A, B, Request> Service<Request> for Either<A, B>
31 where
32     A: Service<Request>,
33     A::Error: Into<Error>,
34     B: Service<Request, Response = A::Response>,
35     B::Error: Into<Error>,
36 {
37     type Response = A::Response;
38     type Error = Error;
39     type Future = Either<A::Future, B::Future>;
40 
poll_ready(&mut self, cx: &mut Context<'_>) -> Poll<Result<(), Self::Error>>41     fn poll_ready(&mut self, cx: &mut Context<'_>) -> Poll<Result<(), Self::Error>> {
42         use self::Either::*;
43 
44         match self {
45             A(service) => Poll::Ready(Ok(ready!(service.poll_ready(cx)).map_err(Into::into)?)),
46             B(service) => Poll::Ready(Ok(ready!(service.poll_ready(cx)).map_err(Into::into)?)),
47         }
48     }
49 
call(&mut self, request: Request) -> Self::Future50     fn call(&mut self, request: Request) -> Self::Future {
51         use self::Either::*;
52 
53         match self {
54             A(service) => A(service.call(request)),
55             B(service) => B(service.call(request)),
56         }
57     }
58 }
59 
60 impl<A, B, T, AE, BE> Future for Either<A, B>
61 where
62     A: Future<Output = Result<T, AE>>,
63     AE: Into<Error>,
64     B: Future<Output = Result<T, BE>>,
65     BE: Into<Error>,
66 {
67     type Output = Result<T, Error>;
68 
69     #[project]
poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output>70     fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
71         #[project]
72         match self.project() {
73             Either::A(fut) => Poll::Ready(Ok(ready!(fut.poll(cx)).map_err(Into::into)?)),
74             Either::B(fut) => Poll::Ready(Ok(ready!(fut.poll(cx)).map_err(Into::into)?)),
75         }
76     }
77 }
78