Skip to main content

ntex_util/future/
either.rs

1use std::{error, fmt, future::Future, io, pin::Pin, task::Context, task::Poll};
2
3use ntex_service::{Ctx, Service};
4
5/// Combines two different futures, streams, or sinks having the same associated types into a single
6/// type.
7#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)]
8pub enum Either<A, B> {
9    /// First branch of the type
10    Left(A),
11    /// Second branch of the type
12    Right(B),
13}
14
15impl<A, B> Either<A, B> {
16    fn project(self: Pin<&mut Self>) -> Either<Pin<&mut A>, Pin<&mut B>> {
17        unsafe {
18            match self.get_unchecked_mut() {
19                Either::Left(a) => Either::Left(Pin::new_unchecked(a)),
20                Either::Right(b) => Either::Right(Pin::new_unchecked(b)),
21            }
22        }
23    }
24
25    #[inline]
26    /// Return true if the value is the `Left` variant.
27    pub fn is_left(&self) -> bool {
28        match *self {
29            Either::Left(_) => true,
30            Either::Right(_) => false,
31        }
32    }
33
34    #[inline]
35    /// Return true if the value is the `Right` variant.
36    pub fn is_right(&self) -> bool {
37        !self.is_left()
38    }
39
40    #[inline]
41    /// Convert the left side of `Either<L, R>` to an `Option<L>`.
42    pub fn left(self) -> Option<A> {
43        match self {
44            Either::Left(l) => Some(l),
45            Either::Right(_) => None,
46        }
47    }
48
49    #[inline]
50    /// Convert the right side of `Either<L, R>` to an `Option<R>`.
51    pub fn right(self) -> Option<B> {
52        match self {
53            Either::Left(_) => None,
54            Either::Right(r) => Some(r),
55        }
56    }
57
58    #[inline]
59    /// Convert `&Either<L, R>` to `Either<&L, &R>`.
60    pub fn as_ref(&self) -> Either<&A, &B> {
61        match *self {
62            Either::Left(ref inner) => Either::Left(inner),
63            Either::Right(ref inner) => Either::Right(inner),
64        }
65    }
66
67    #[inline]
68    /// Convert `&mut Either<L, R>` to `Either<&mut L, &mut R>`.
69    pub fn as_mut(&mut self) -> Either<&mut A, &mut B> {
70        match *self {
71            Either::Left(ref mut inner) => Either::Left(inner),
72            Either::Right(ref mut inner) => Either::Right(inner),
73        }
74    }
75}
76
77impl<T> Either<T, T> {
78    #[inline]
79    /// Extract the value of an either over two equivalent types.
80    pub fn into_inner(self) -> T {
81        match self {
82            Either::Left(x) | Either::Right(x) => x,
83        }
84    }
85}
86
87/// `Either` implements `Error` if *both* `A` and `B` implement it.
88impl<A, B> error::Error for Either<A, B>
89where
90    A: error::Error,
91    B: error::Error,
92{
93    fn source(&self) -> Option<&(dyn error::Error + 'static)> {
94        match self {
95            Either::Left(a) => a.source(),
96            Either::Right(b) => b.source(),
97        }
98    }
99}
100
101impl<A, B> fmt::Display for Either<A, B>
102where
103    A: fmt::Display,
104    B: fmt::Display,
105{
106    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
107        match self {
108            Either::Left(a) => a.fmt(f),
109            Either::Right(b) => b.fmt(f),
110        }
111    }
112}
113
114impl<A, B> Future for Either<A, B>
115where
116    A: Future,
117    B: Future<Output = A::Output>,
118{
119    type Output = A::Output;
120
121    #[inline]
122    fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
123        match self.project() {
124            Either::Left(x) => x.poll(cx),
125            Either::Right(x) => x.poll(cx),
126        }
127    }
128}
129
130impl<E: error::Error> From<Either<E, io::Error>> for io::Error {
131    fn from(err: Either<E, io::Error>) -> Self {
132        match err {
133            Either::Left(e) => io::Error::other(format!("{e:?}")),
134            Either::Right(e) => e,
135        }
136    }
137}
138
139impl<A, B, St, Req> Service<St, Req> for Either<A, B>
140where
141    A: Service<St, Req>,
142    B: Service<St, Req, Res = A::Res, Error = A::Error>,
143{
144    type Res = A::Res;
145    type Error = A::Error;
146
147    async fn call(&self, req: Req, ctx: Ctx<'_, Self, St>) -> Result<Self::Res, Self::Error> {
148        match self {
149            Either::Left(svc) => ctx.call(svc, req).await,
150            Either::Right(svc) => ctx.call(svc, req).await,
151        }
152    }
153
154    async fn ready(&self, ctx: Ctx<'_, Self, St>) -> Result<(), Self::Error> {
155        match self {
156            Either::Left(svc) => ctx.ready(svc).await,
157            Either::Right(svc) => ctx.ready(svc).await,
158        }
159    }
160
161    async fn shutdown(&self, ctx: Ctx<'_, Self, St>) {
162        match self {
163            Either::Left(svc) => ctx.shutdown(svc).await,
164            Either::Right(svc) => ctx.shutdown(svc).await,
165        }
166    }
167}
168
169#[cfg(test)]
170mod test {
171    use super::*;
172
173    #[test]
174    #[allow(clippy::unit_cmp)]
175    fn either() {
176        let mut e = Either::<(), ()>::Left(());
177        assert!(e.is_left());
178        assert!(!e.is_right());
179        assert!(e.left().is_some());
180        assert!(e.right().is_none());
181        e.as_ref();
182        e.as_mut();
183
184        let mut e = Either::<(), ()>::Right(());
185        assert!(!e.is_left());
186        assert!(e.is_right());
187        assert!(e.left().is_none());
188        assert!(e.right().is_some());
189        e.as_ref();
190        e.as_mut();
191
192        assert_eq!(Either::<(), ()>::Left(()).into_inner(), ());
193        assert_eq!(Either::<(), ()>::Right(()).into_inner(), ());
194
195        assert_eq!(
196            format!("{}", Either::<_, &'static str>::Left("test")),
197            "test"
198        );
199        assert_eq!(
200            format!("{}", Either::<&'static str, _>::Right("test")),
201            "test"
202        );
203    }
204}