• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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