service_async/
either.rs

1use std::{error::Error, fmt::Display, future::Future, pin::Pin};
2
3use crate::{layer::FactoryLayer, AsyncMakeService, MakeService, Service};
4
5/// An Enum representing a value of one of two possible types.
6///
7/// `Either<A, B>` is particularly useful in service composition and layered architectures.
8///
9/// `Either` allows for conditional inclusion of layers in a service stack:
10///
11/// ```rust
12///
13/// impl<T> SvcC<T> {
14///    fn layer<C>() -> impl FactoryLayer<C, T, Factory = Self> {
15///       layer_fn(|_: &C, inner| SvcC { inner })
16///    }
17///
18///   fn opt_layer<C>(enabled: bool) -> Option<impl FactoryLayer<C, T, Factory = Self>> {
19///       if enabled {
20///           Some(layer_fn(|_: &C, inner| SvcC { inner }))
21///       } else {
22///           None
23///       }
24///    }
25/// }
26///
27/// let stack = FactoryStack::new(config)
28///     .push(SvcAFactory::layer())
29///     .push(SvcBFactory::layer())
30///     .push(SvcC::opt_layer(true));  // Conditionally include SvcC
31/// ```
32///
33/// This pattern enables runtime control over the service composition, making it possible to
34/// dynamically include or exclude certain layers based on configuration or runtime conditions.
35///
36#[derive(Debug, Clone)]
37pub enum Either<A, B> {
38    Left(A),
39    Right(B),
40}
41
42impl<C, F, T> FactoryLayer<C, F> for Option<T>
43where
44    T: FactoryLayer<C, F>,
45{
46    type Factory = Either<T::Factory, F>;
47
48    #[inline]
49    fn layer(&self, config: &C, inner: F) -> Self::Factory {
50        match self {
51            Some(fl) => Either::Left(fl.layer(config, inner)),
52            None => Either::Right(inner),
53        }
54    }
55}
56
57impl<C, F, FLA, FLB> FactoryLayer<C, F> for Either<FLA, FLB>
58where
59    FLA: FactoryLayer<C, F>,
60    FLB: FactoryLayer<C, F>,
61{
62    type Factory = Either<FLA::Factory, FLB::Factory>;
63
64    #[inline]
65    fn layer(&self, config: &C, inner: F) -> Self::Factory {
66        match self {
67            Either::Left(fl) => Either::Left(fl.layer(config, inner)),
68            Either::Right(fl) => Either::Right(fl.layer(config, inner)),
69        }
70    }
71}
72
73impl<A, B> MakeService for Either<A, B>
74where
75    A: MakeService,
76    B: MakeService,
77{
78    type Service = Either<A::Service, B::Service>;
79    type Error = Either<A::Error, B::Error>;
80
81    fn make_via_ref(&self, old: Option<&Self::Service>) -> Result<Self::Service, Self::Error> {
82        match self {
83            Either::Left(f) => match old.as_ref() {
84                Some(Either::Left(left_svc)) => f.make_via_ref(Some(left_svc)),
85                _ => f.make(),
86            }
87            .map(Either::Left)
88            .map_err(Either::Left),
89            Either::Right(f) => match old.as_ref() {
90                Some(Either::Right(right_svc)) => f.make_via_ref(Some(right_svc)),
91                _ => f.make(),
92            }
93            .map(Either::Right)
94            .map_err(Either::Right),
95        }
96    }
97}
98
99impl<A, B> AsyncMakeService for Either<A, B>
100where
101    A: AsyncMakeService,
102    B: AsyncMakeService,
103{
104    type Service = Either<A::Service, B::Service>;
105    type Error = Either<A::Error, B::Error>;
106
107    async fn make_via_ref(
108        &self,
109        old: Option<&Self::Service>,
110    ) -> Result<Self::Service, Self::Error> {
111        match self {
112            Either::Left(f) => match old.as_ref() {
113                Some(Either::Left(left_svc)) => f.make_via_ref(Some(left_svc)).await,
114                _ => f.make().await,
115            }
116            .map(Either::Left)
117            .map_err(Either::Left),
118            Either::Right(f) => match old.as_ref() {
119                Some(Either::Right(right_svc)) => f.make_via_ref(Some(right_svc)).await,
120                _ => f.make().await,
121            }
122            .map(Either::Right)
123            .map_err(Either::Right),
124        }
125    }
126}
127
128impl<A, B, R> Service<R> for Either<A, B>
129where
130    A: Service<R>,
131    B: Service<R, Response = A::Response, Error = A::Error>,
132{
133    type Response = A::Response;
134    type Error = A::Error;
135
136    #[inline]
137    fn call(&self, req: R) -> impl Future<Output = Result<Self::Response, Self::Error>> {
138        match self {
139            Either::Left(s) => Either::Left(s.call(req)),
140            Either::Right(s) => Either::Right(s.call(req)),
141        }
142    }
143}
144
145impl<A, B> Future for Either<A, B>
146where
147    A: Future,
148    B: Future<Output = A::Output>,
149{
150    type Output = A::Output;
151
152    #[inline]
153    fn poll(
154        self: std::pin::Pin<&mut Self>,
155        cx: &mut std::task::Context<'_>,
156    ) -> std::task::Poll<Self::Output> {
157        match self.as_pin_mut() {
158            Either::Left(fut) => fut.poll(cx),
159            Either::Right(fut) => fut.poll(cx),
160        }
161    }
162}
163
164// Copied from futures-util.
165impl<A, B> Either<A, B> {
166    /// Convert `Pin<&Either<A, B>>` to `Either<Pin<&A>, Pin<&B>>`,
167    /// pinned projections of the inner variants.
168    #[inline]
169    pub fn as_pin_ref(self: Pin<&Self>) -> Either<Pin<&A>, Pin<&B>> {
170        // SAFETY: We can use `new_unchecked` because the `inner` parts are
171        // guaranteed to be pinned, as they come from `self` which is pinned.
172        unsafe {
173            match *Pin::get_ref(self) {
174                Either::Left(ref inner) => Either::Left(Pin::new_unchecked(inner)),
175                Either::Right(ref inner) => Either::Right(Pin::new_unchecked(inner)),
176            }
177        }
178    }
179
180    /// Convert `Pin<&mut Either<A, B>>` to `Either<Pin<&mut A>, Pin<&mut B>>`,
181    /// pinned projections of the inner variants.
182    #[inline]
183    pub fn as_pin_mut(self: Pin<&mut Self>) -> Either<Pin<&mut A>, Pin<&mut B>> {
184        // SAFETY: `get_unchecked_mut` is fine because we don't move anything.
185        // We can use `new_unchecked` because the `inner` parts are guaranteed
186        // to be pinned, as they come from `self` which is pinned, and we never
187        // offer an unpinned `&mut A` or `&mut B` through `Pin<&mut Self>`. We
188        // also don't have an implementation of `Drop`, nor manual `Unpin`.
189        unsafe {
190            match *Pin::get_unchecked_mut(self) {
191                Either::Left(ref mut inner) => Either::Left(Pin::new_unchecked(inner)),
192                Either::Right(ref mut inner) => Either::Right(Pin::new_unchecked(inner)),
193            }
194        }
195    }
196}
197
198impl<A: Display, B: Display> Display for Either<A, B> {
199    #[inline]
200    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
201        match self {
202            Either::Left(inner) => inner.fmt(f),
203            Either::Right(inner) => inner.fmt(f),
204        }
205    }
206}
207
208impl<A: Error, B: Error> Error for Either<A, B> {
209    fn source(&self) -> Option<&(dyn Error + 'static)> {
210        match self {
211            Either::Left(inner) => inner.source(),
212            Either::Right(inner) => inner.source(),
213        }
214    }
215}
216
217impl<T> Either<T, T> {
218    #[inline]
219    pub fn into_inner(self) -> T {
220        match self {
221            Either::Left(t) => t,
222            Either::Right(t) => t,
223        }
224    }
225}