burger/
either.rs

1//! Often we want the branches of a runtime condition to output different service types. The
2//! [`Either`] [`Service`] allows the reconciliation of two separate types. The [`Either::Left`]
3//! and [`Either::Right`] variants can be constructed by
4//! [`ServiceExt::left`](crate::ServiceExt::left) and
5//! [`ServiceExt::right`](crate::ServiceExt::right) respectively.
6//!
7//! # Example
8//!
9//! ```rust
10//! use burger::*;
11//!
12//! # #[tokio::main]
13//! # async fn main() {
14//! # let max_concurrency = Some(3);
15//! let svc = service_fn(|x| async move { x + 2 });
16//! let svc = if let Some(some) = max_concurrency {
17//!     svc.concurrency_limit(some).load_shed().left()
18//! } else {
19//!     svc.load_shed().right()
20//! };
21//! let response = svc.oneshot(10u32).await;
22//! # }
23//! ```
24//!
25//! # Load
26//!
27//! The [`Load::load`] on [`Either`] defers to the variant.
28
29use crate::{load::Load, Service};
30
31/// A wrapper [`Service`] for [`ServiceExt::left`](crate::ServiceExt::left) and
32/// [`ServiceExt::right`](crate::ServiceExt::right) which consolidates two types.
33///
34/// See the [module](mod@crate::either) for more information.
35#[derive(Debug)]
36pub enum Either<A, B> {
37    #[allow(missing_docs)]
38    Left(A),
39    #[allow(missing_docs)]
40    Right(B),
41}
42
43impl<Request, A, B> Service<Request> for Either<A, B>
44where
45    A: Service<Request>,
46    B: Service<Request, Response = A::Response>,
47{
48    type Response = A::Response;
49    type Permit<'a> = Either<A::Permit<'a>, B::Permit<'a>>
50    where
51        Self: 'a;
52
53    async fn acquire(&self) -> Self::Permit<'_> {
54        match self {
55            Either::Left(left) => Either::Left(left.acquire().await),
56            Either::Right(right) => Either::Right(right.acquire().await),
57        }
58    }
59
60    async fn call<'a>(permit: Self::Permit<'a>, request: Request) -> Self::Response
61    where
62        Self: 'a,
63    {
64        match permit {
65            Either::Left(permit) => A::call(permit, request).await,
66            Either::Right(permit) => B::call(permit, request).await,
67        }
68    }
69}
70
71impl<A, B> Load for Either<A, B>
72where
73    A: Load,
74    B: Load<Metric = A::Metric>,
75{
76    type Metric = A::Metric;
77
78    fn load(&self) -> Self::Metric {
79        match self {
80            Either::Left(left) => left.load(),
81            Either::Right(right) => right.load(),
82        }
83    }
84}