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}