async_macros/
maybe_done.rs

1//! A type that wraps a future to keep track of its completion status.
2//!
3//! This implementation was taken from the original `macro_rules` `join/try_join`
4//! macros in the `futures-preview` crate.
5
6use core::future::Future;
7use core::mem;
8use core::pin::Pin;
9
10use futures_core::ready;
11use futures_core::task::{Context, Poll};
12
13/// A future that may have completed.
14#[derive(Debug)]
15pub enum MaybeDone<Fut: Future> {
16    /// A not-yet-completed future
17    Future(Fut),
18    /// The output of the completed future
19    Done(Fut::Output),
20    /// The empty variant after the result of a [`MaybeDone`] has been
21    /// taken using the [`take`](MaybeDone::take) method.
22    Gone,
23}
24
25impl<Fut: Future> MaybeDone<Fut> {
26    /// Create a new instance of `MaybeDone`.
27    pub fn new(future: Fut) -> MaybeDone<Fut> {
28        Self::Future(future)
29    }
30
31    /// Returns an [`Option`] containing a reference to the output of the future.
32    /// The output of this method will be [`Some`] if and only if the inner
33    /// future has been completed and [`take`](MaybeDone::take)
34    /// has not yet been called.
35    #[inline]
36    pub fn output(self: Pin<&Self>) -> Option<&Fut::Output> {
37        let this = self.get_ref();
38        match this {
39            MaybeDone::Done(res) => Some(res),
40            _ => None,
41        }
42    }
43
44    /// Returns an [`Option`] containing a mutable reference to the output of the future.
45    /// The output of this method will be [`Some`] if and only if the inner
46    /// future has been completed and [`take`](MaybeDone::take)
47    /// has not yet been called.
48    #[inline]
49    pub fn output_mut(self: Pin<&mut Self>) -> Option<&mut Fut::Output> {
50        unsafe {
51            let this = self.get_unchecked_mut();
52            match this {
53                MaybeDone::Done(res) => Some(res),
54                _ => None,
55            }
56        }
57    }
58
59    /// Attempt to take the output of a `MaybeDone` without driving it
60    /// towards completion.
61    #[inline]
62    pub fn take(self: Pin<&mut Self>) -> Option<Fut::Output> {
63        unsafe {
64            let this = self.get_unchecked_mut();
65            match this {
66                MaybeDone::Done(_) => {}
67                MaybeDone::Future(_) | MaybeDone::Gone => return None,
68            };
69            if let MaybeDone::Done(output) = mem::replace(this, MaybeDone::Gone) {
70                Some(output)
71            } else {
72                unreachable!()
73            }
74        }
75    }
76
77    // fn ok(self) -> Option<Fut::Output> {}
78}
79
80impl<Fut: Future> Future for MaybeDone<Fut> {
81    type Output = ();
82
83    fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
84        let res = unsafe {
85            match Pin::as_mut(&mut self).get_unchecked_mut() {
86                MaybeDone::Future(a) => ready!(Pin::new_unchecked(a).poll(cx)),
87                MaybeDone::Done(_) => return Poll::Ready(()),
88                MaybeDone::Gone => panic!("MaybeDone polled after value taken"),
89            }
90        };
91        self.set(MaybeDone::Done(res));
92        Poll::Ready(())
93    }
94}