|
| 1 | +use super::assert_future; |
| 2 | +use crate::future::{Either, FutureExt}; |
| 3 | +use core::pin::Pin; |
| 4 | +use futures_core::future::{FusedFuture, Future}; |
| 5 | +use futures_core::task::{Context, Poll}; |
| 6 | + |
| 7 | +/// Future for the [`select_biased()`] function. |
| 8 | +#[must_use = "futures do nothing unless you `.await` or poll them"] |
| 9 | +#[derive(Debug)] |
| 10 | +pub struct SelectBiased<A, B> { |
| 11 | + inner: Option<(A, B)>, |
| 12 | +} |
| 13 | + |
| 14 | +impl<A: Unpin, B: Unpin> Unpin for SelectBiased<A, B> {} |
| 15 | + |
| 16 | +/// Waits for either one of two differently-typed futures to complete, giving preferential treatment to the first argument. |
| 17 | +/// |
| 18 | +/// This function will return a new future which awaits for either one of both |
| 19 | +/// futures to complete. The returned future will finish with both the value |
| 20 | +/// resolved and a future representing the completion of the other work. |
| 21 | +/// |
| 22 | +/// Note that this function consumes the receiving futures and returns a |
| 23 | +/// wrapped version of them. |
| 24 | +/// |
| 25 | +/// **If both futures are ready when this is polled, the first argument will always be selected.** |
| 26 | +/// |
| 27 | +/// Also note that if both this and the second future have the same |
| 28 | +/// output type you can use the `Either::factor_first` method to |
| 29 | +/// conveniently extract out the value at the end. |
| 30 | +/// |
| 31 | +/// # Examples |
| 32 | +/// |
| 33 | +/// A simple example |
| 34 | +/// |
| 35 | +/// ``` |
| 36 | +/// # futures::executor::block_on(async { |
| 37 | +/// use futures::{ |
| 38 | +/// pin_mut, |
| 39 | +/// future::Either, |
| 40 | +/// future::self, |
| 41 | +/// }; |
| 42 | +/// |
| 43 | +/// // These two futures have different types even though their outputs have the same type. |
| 44 | +/// let future1 = async { |
| 45 | +/// future::pending::<()>().await; // will never finish |
| 46 | +/// 1 |
| 47 | +/// }; |
| 48 | +/// let future2 = async { |
| 49 | +/// future::ready(2).await |
| 50 | +/// }; |
| 51 | +/// |
| 52 | +/// // 'select_biased' requires Future + Unpin bounds |
| 53 | +/// pin_mut!(future1); |
| 54 | +/// pin_mut!(future2); |
| 55 | +/// |
| 56 | +/// let value = match future::select_biased(future1, future2).await { |
| 57 | +/// Either::Left((value1, _)) => value1, // `value1` is resolved from `future1` |
| 58 | +/// // `_` represents `future2` |
| 59 | +/// Either::Right((value2, _)) => value2, // `value2` is resolved from `future2` |
| 60 | +/// // `_` represents `future1` |
| 61 | +/// }; |
| 62 | +/// |
| 63 | +/// assert!(value == 2); |
| 64 | +/// # }); |
| 65 | +/// ``` |
| 66 | +/// |
| 67 | +/// A more complex example |
| 68 | +/// |
| 69 | +/// ``` |
| 70 | +/// use futures::future::{self, Either, Future, FutureExt}; |
| 71 | +/// |
| 72 | +/// // A poor-man's join implemented on top of select_biased |
| 73 | +/// |
| 74 | +/// fn join<A, B>(a: A, b: B) -> impl Future<Output=(A::Output, B::Output)> |
| 75 | +/// where A: Future + Unpin, |
| 76 | +/// B: Future + Unpin, |
| 77 | +/// { |
| 78 | +/// future::select_biased(a, b).then(|either| { |
| 79 | +/// match either { |
| 80 | +/// Either::Left((x, b)) => b.map(move |y| (x, y)).left_future(), |
| 81 | +/// Either::Right((y, a)) => a.map(move |x| (x, y)).right_future(), |
| 82 | +/// } |
| 83 | +/// }) |
| 84 | +/// } |
| 85 | +/// ``` |
| 86 | +pub fn select_biased<A, B>(future1: A, future2: B) -> SelectBiased<A, B> |
| 87 | +where |
| 88 | + A: Future + Unpin, |
| 89 | + B: Future + Unpin, |
| 90 | +{ |
| 91 | + assert_future::<Either<(A::Output, B), (B::Output, A)>, _>(SelectBiased { |
| 92 | + inner: Some((future1, future2)), |
| 93 | + }) |
| 94 | +} |
| 95 | + |
| 96 | +impl<A, B> Future for SelectBiased<A, B> |
| 97 | +where |
| 98 | + A: Future + Unpin, |
| 99 | + B: Future + Unpin, |
| 100 | +{ |
| 101 | + type Output = Either<(A::Output, B), (B::Output, A)>; |
| 102 | + |
| 103 | + fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> { |
| 104 | + /// When compiled with `-C opt-level=z`, this function will help the compiler eliminate the `None` branch, where |
| 105 | + /// `Option::unwrap` does not. |
| 106 | + #[inline(always)] |
| 107 | + fn unwrap_option<T>(value: Option<T>) -> T { |
| 108 | + match value { |
| 109 | + None => unreachable!(), |
| 110 | + Some(value) => value, |
| 111 | + } |
| 112 | + } |
| 113 | + |
| 114 | + let (a, b) = self.inner.as_mut().expect("cannot poll Select twice"); |
| 115 | + |
| 116 | + macro_rules! poll_wrap { |
| 117 | + ($to_poll:expr, $unpolled:expr, $wrap:expr) => { |
| 118 | + if let Poll::Ready(val) = $to_poll.poll_unpin(cx) { |
| 119 | + return Poll::Ready($wrap((val, $unpolled))); |
| 120 | + } |
| 121 | + }; |
| 122 | + } |
| 123 | + |
| 124 | + poll_wrap!(a, unwrap_option(self.inner.take()).1, Either::Left); |
| 125 | + poll_wrap!(b, unwrap_option(self.inner.take()).0, Either::Right); |
| 126 | + Poll::Pending |
| 127 | + } |
| 128 | +} |
| 129 | + |
| 130 | +impl<A, B> FusedFuture for SelectBiased<A, B> |
| 131 | +where |
| 132 | + A: Future + Unpin, |
| 133 | + B: Future + Unpin, |
| 134 | +{ |
| 135 | + fn is_terminated(&self) -> bool { |
| 136 | + self.inner.is_none() |
| 137 | + } |
| 138 | +} |
0 commit comments