1 //! Definition of the MaybeDone combinator
2
3 use std::future::Future;
4 use std::mem;
5 use std::pin::Pin;
6 use std::task::{Context, Poll};
7
8 /// A future that may have completed.
9 #[derive(Debug)]
10 pub enum MaybeDone<Fut: Future> {
11 /// A not-yet-completed future
12 Future(Fut),
13 /// The output of the completed future
14 Done(Fut::Output),
15 /// The empty variant after the result of a [`MaybeDone`] has been
16 /// taken using the [`take_output`](MaybeDone::take_output) method.
17 Gone,
18 }
19
20 // Safe because we never generate `Pin<&mut Fut::Output>`
21 impl<Fut: Future + Unpin> Unpin for MaybeDone<Fut> {}
22
23 /// Wraps a future into a `MaybeDone`
maybe_done<Fut: Future>(future: Fut) -> MaybeDone<Fut>24 pub fn maybe_done<Fut: Future>(future: Fut) -> MaybeDone<Fut> {
25 MaybeDone::Future(future)
26 }
27
28 impl<Fut: Future> MaybeDone<Fut> {
29 /// Returns an [`Option`] containing a mutable reference to the output of the future.
30 /// The output of this method will be [`Some`] if and only if the inner
31 /// future has been completed and [`take_output`](MaybeDone::take_output)
32 /// has not yet been called.
output_mut(self: Pin<&mut Self>) -> Option<&mut Fut::Output>33 pub fn output_mut(self: Pin<&mut Self>) -> Option<&mut Fut::Output> {
34 unsafe {
35 let this = self.get_unchecked_mut();
36 match this {
37 MaybeDone::Done(res) => Some(res),
38 _ => None,
39 }
40 }
41 }
42
43 /// Attempts to take the output of a `MaybeDone` without driving it
44 /// towards completion.
45 #[inline]
take_output(self: Pin<&mut Self>) -> Option<Fut::Output>46 pub fn take_output(self: Pin<&mut Self>) -> Option<Fut::Output> {
47 unsafe {
48 let this = self.get_unchecked_mut();
49 match this {
50 MaybeDone::Done(_) => {}
51 MaybeDone::Future(_) | MaybeDone::Gone => return None,
52 };
53 if let MaybeDone::Done(output) = mem::replace(this, MaybeDone::Gone) {
54 Some(output)
55 } else {
56 unreachable!()
57 }
58 }
59 }
60 }
61
62 impl<Fut: Future> Future for MaybeDone<Fut> {
63 type Output = ();
64
poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output>65 fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
66 let res = unsafe {
67 match self.as_mut().get_unchecked_mut() {
68 MaybeDone::Future(a) => ready!(Pin::new_unchecked(a).poll(cx)),
69 MaybeDone::Done(_) => return Poll::Ready(()),
70 MaybeDone::Gone => panic!("MaybeDone polled after value taken"),
71 }
72 };
73 self.set(MaybeDone::Done(res));
74 Poll::Ready(())
75 }
76 }
77