futures_util/future/
either.rs

1use core::pin::Pin;
2use core::task::{Context, Poll};
3use futures_core::future::{FusedFuture, Future};
4use futures_core::stream::{FusedStream, Stream};
5#[cfg(feature = "sink")]
6use futures_sink::Sink;
7
8/// Combines two different futures, streams, or sinks having the same associated types into a single type.
9///
10/// This is useful when conditionally choosing between two distinct future types:
11///
12/// ```rust
13/// use futures::future::Either;
14///
15/// # futures::executor::block_on(async {
16/// let cond = true;
17///
18/// let fut = if cond {
19///     Either::Left(async move { 12 })
20/// } else {
21///     Either::Right(async move { 44 })
22/// };
23///
24/// assert_eq!(fut.await, 12);
25/// # })
26/// ```
27#[derive(Debug, Clone)]
28pub enum Either<A, B> {
29    /// First branch of the type
30    Left(/* #[pin] */ A),
31    /// Second branch of the type
32    Right(/* #[pin] */ B),
33}
34
35impl<A, B> Either<A, B> {
36    fn project(self: Pin<&mut Self>) -> Either<Pin<&mut A>, Pin<&mut B>> {
37        unsafe {
38            match self.get_unchecked_mut() {
39                Either::Left(a) => Either::Left(Pin::new_unchecked(a)),
40                Either::Right(b) => Either::Right(Pin::new_unchecked(b)),
41            }
42        }
43    }
44}
45
46impl<A, B, T> Either<(T, A), (T, B)> {
47    /// Factor out a homogeneous type from an either of pairs.
48    ///
49    /// Here, the homogeneous type is the first element of the pairs.
50    pub fn factor_first(self) -> (T, Either<A, B>) {
51        match self {
52            Either::Left((x, a)) => (x, Either::Left(a)),
53            Either::Right((x, b)) => (x, Either::Right(b)),
54        }
55    }
56}
57
58impl<A, B, T> Either<(A, T), (B, T)> {
59    /// Factor out a homogeneous type from an either of pairs.
60    ///
61    /// Here, the homogeneous type is the second element of the pairs.
62    pub fn factor_second(self) -> (Either<A, B>, T) {
63        match self {
64            Either::Left((a, x)) => (Either::Left(a), x),
65            Either::Right((b, x)) => (Either::Right(b), x),
66        }
67    }
68}
69
70impl<T> Either<T, T> {
71    /// Extract the value of an either over two equivalent types.
72    pub fn into_inner(self) -> T {
73        match self {
74            Either::Left(x) => x,
75            Either::Right(x) => x,
76        }
77    }
78}
79
80impl<A, B> Future for Either<A, B>
81where
82    A: Future,
83    B: Future<Output = A::Output>,
84{
85    type Output = A::Output;
86
87    fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
88        match self.project() {
89            Either::Left(x) => x.poll(cx),
90            Either::Right(x) => x.poll(cx),
91        }
92    }
93}
94
95impl<A, B> FusedFuture for Either<A, B>
96where
97    A: FusedFuture,
98    B: FusedFuture<Output = A::Output>,
99{
100    fn is_terminated(&self) -> bool {
101        match self {
102            Either::Left(x) => x.is_terminated(),
103            Either::Right(x) => x.is_terminated(),
104        }
105    }
106}
107
108impl<A, B> Stream for Either<A, B>
109where
110    A: Stream,
111    B: Stream<Item = A::Item>,
112{
113    type Item = A::Item;
114
115    fn poll_next(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Option<Self::Item>> {
116        match self.project() {
117            Either::Left(x) => x.poll_next(cx),
118            Either::Right(x) => x.poll_next(cx),
119        }
120    }
121
122    fn size_hint(&self) -> (usize, Option<usize>) {
123        match self {
124            Either::Left(x) => x.size_hint(),
125            Either::Right(x) => x.size_hint(),
126        }
127    }
128}
129
130impl<A, B> FusedStream for Either<A, B>
131where
132    A: FusedStream,
133    B: FusedStream<Item = A::Item>,
134{
135    fn is_terminated(&self) -> bool {
136        match self {
137            Either::Left(x) => x.is_terminated(),
138            Either::Right(x) => x.is_terminated(),
139        }
140    }
141}
142
143#[cfg(feature = "sink")]
144impl<A, B, Item> Sink<Item> for Either<A, B>
145where
146    A: Sink<Item>,
147    B: Sink<Item, Error = A::Error>,
148{
149    type Error = A::Error;
150
151    fn poll_ready(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Result<(), Self::Error>> {
152        match self.project() {
153            Either::Left(x) => x.poll_ready(cx),
154            Either::Right(x) => x.poll_ready(cx),
155        }
156    }
157
158    fn start_send(self: Pin<&mut Self>, item: Item) -> Result<(), Self::Error> {
159        match self.project() {
160            Either::Left(x) => x.start_send(item),
161            Either::Right(x) => x.start_send(item),
162        }
163    }
164
165    fn poll_flush(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Result<(), Self::Error>> {
166        match self.project() {
167            Either::Left(x) => x.poll_flush(cx),
168            Either::Right(x) => x.poll_flush(cx),
169        }
170    }
171
172    fn poll_close(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Result<(), Self::Error>> {
173        match self.project() {
174            Either::Left(x) => x.poll_close(cx),
175            Either::Right(x) => x.poll_close(cx),
176        }
177    }
178}
179
180#[cfg(feature = "io")]
181#[cfg(feature = "std")]
182mod if_std {
183    use super::*;
184
185    use core::pin::Pin;
186    use core::task::{Context, Poll};
187    use futures_io::{
188        AsyncBufRead, AsyncRead, AsyncSeek, AsyncWrite, IoSlice, IoSliceMut, Result, SeekFrom,
189    };
190
191    impl<A, B> AsyncRead for Either<A, B>
192    where
193        A: AsyncRead,
194        B: AsyncRead,
195    {
196        fn poll_read(
197            self: Pin<&mut Self>,
198            cx: &mut Context<'_>,
199            buf: &mut [u8],
200        ) -> Poll<Result<usize>> {
201            match self.project() {
202                Either::Left(x) => x.poll_read(cx, buf),
203                Either::Right(x) => x.poll_read(cx, buf),
204            }
205        }
206
207        fn poll_read_vectored(
208            self: Pin<&mut Self>,
209            cx: &mut Context<'_>,
210            bufs: &mut [IoSliceMut<'_>],
211        ) -> Poll<Result<usize>> {
212            match self.project() {
213                Either::Left(x) => x.poll_read_vectored(cx, bufs),
214                Either::Right(x) => x.poll_read_vectored(cx, bufs),
215            }
216        }
217    }
218
219    impl<A, B> AsyncWrite for Either<A, B>
220    where
221        A: AsyncWrite,
222        B: AsyncWrite,
223    {
224        fn poll_write(
225            self: Pin<&mut Self>,
226            cx: &mut Context<'_>,
227            buf: &[u8],
228        ) -> Poll<Result<usize>> {
229            match self.project() {
230                Either::Left(x) => x.poll_write(cx, buf),
231                Either::Right(x) => x.poll_write(cx, buf),
232            }
233        }
234
235        fn poll_write_vectored(
236            self: Pin<&mut Self>,
237            cx: &mut Context<'_>,
238            bufs: &[IoSlice<'_>],
239        ) -> Poll<Result<usize>> {
240            match self.project() {
241                Either::Left(x) => x.poll_write_vectored(cx, bufs),
242                Either::Right(x) => x.poll_write_vectored(cx, bufs),
243            }
244        }
245
246        fn poll_flush(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Result<()>> {
247            match self.project() {
248                Either::Left(x) => x.poll_flush(cx),
249                Either::Right(x) => x.poll_flush(cx),
250            }
251        }
252
253        fn poll_close(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Result<()>> {
254            match self.project() {
255                Either::Left(x) => x.poll_close(cx),
256                Either::Right(x) => x.poll_close(cx),
257            }
258        }
259    }
260
261    impl<A, B> AsyncSeek for Either<A, B>
262    where
263        A: AsyncSeek,
264        B: AsyncSeek,
265    {
266        fn poll_seek(
267            self: Pin<&mut Self>,
268            cx: &mut Context<'_>,
269            pos: SeekFrom,
270        ) -> Poll<Result<u64>> {
271            match self.project() {
272                Either::Left(x) => x.poll_seek(cx, pos),
273                Either::Right(x) => x.poll_seek(cx, pos),
274            }
275        }
276    }
277
278    impl<A, B> AsyncBufRead for Either<A, B>
279    where
280        A: AsyncBufRead,
281        B: AsyncBufRead,
282    {
283        fn poll_fill_buf(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Result<&[u8]>> {
284            match self.project() {
285                Either::Left(x) => x.poll_fill_buf(cx),
286                Either::Right(x) => x.poll_fill_buf(cx),
287            }
288        }
289
290        fn consume(self: Pin<&mut Self>, amt: usize) {
291            match self.project() {
292                Either::Left(x) => x.consume(amt),
293                Either::Right(x) => x.consume(amt),
294            }
295        }
296    }
297}