tower/util/
either.rs

1//! Contains [`Either`] and related types and functions.
2//!
3//! See [`Either`] documentation for more details.
4
5use pin_project_lite::pin_project;
6use std::{
7    future::Future,
8    pin::Pin,
9    task::{Context, Poll},
10};
11use tower_layer::Layer;
12use 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#[derive(Clone, Copy, Debug)]
20pub enum Either<A, B> {
21    #[allow(missing_docs)]
22    Left(A),
23    #[allow(missing_docs)]
24    Right(B),
25}
26
27impl<A, B, Request> Service<Request> for Either<A, B>
28where
29    A: Service<Request>,
30    B: Service<Request, Response = A::Response, Error = A::Error>,
31{
32    type Response = A::Response;
33    type Error = A::Error;
34    type Future = EitherResponseFuture<A::Future, B::Future>;
35
36    fn poll_ready(&mut self, cx: &mut Context<'_>) -> Poll<Result<(), Self::Error>> {
37        match self {
38            Either::Left(service) => service.poll_ready(cx),
39            Either::Right(service) => service.poll_ready(cx),
40        }
41    }
42
43    fn call(&mut self, request: Request) -> Self::Future {
44        match self {
45            Either::Left(service) => EitherResponseFuture {
46                kind: Kind::Left {
47                    inner: service.call(request),
48                },
49            },
50            Either::Right(service) => EitherResponseFuture {
51                kind: Kind::Right {
52                    inner: service.call(request),
53                },
54            },
55        }
56    }
57}
58
59pin_project! {
60    /// Response future for [`Either`].
61    pub struct EitherResponseFuture<A, B> {
62        #[pin]
63        kind: Kind<A, B>
64    }
65}
66
67pin_project! {
68    #[project = KindProj]
69    enum Kind<A, B> {
70        Left { #[pin] inner: A },
71        Right { #[pin] inner: B },
72    }
73}
74
75impl<A, B> Future for EitherResponseFuture<A, B>
76where
77    A: Future,
78    B: Future<Output = A::Output>,
79{
80    type Output = A::Output;
81
82    fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
83        match self.project().kind.project() {
84            KindProj::Left { inner } => inner.poll(cx),
85            KindProj::Right { inner } => inner.poll(cx),
86        }
87    }
88}
89
90impl<S, A, B> Layer<S> for Either<A, B>
91where
92    A: Layer<S>,
93    B: Layer<S>,
94{
95    type Service = Either<A::Service, B::Service>;
96
97    fn layer(&self, inner: S) -> Self::Service {
98        match self {
99            Either::Left(layer) => Either::Left(layer.layer(inner)),
100            Either::Right(layer) => Either::Right(layer.layer(inner)),
101        }
102    }
103}