tower/util/
either.rs

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