Skip to main content

ntex_util/future/
either.rs

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