1 | //! Definition of the MaybeDone combinator |
2 | |
3 | use super::assert_future; |
4 | use core::mem; |
5 | use core::pin::Pin; |
6 | use futures_core::future::{FusedFuture, Future}; |
7 | use futures_core::ready; |
8 | use futures_core::task::{Context, Poll}; |
9 | |
10 | /// A future that may have completed. |
11 | /// |
12 | /// This is created by the [`maybe_done()`] function. |
13 | #[derive(Debug)] |
14 | pub enum MaybeDone<Fut: Future> { |
15 | /// A not-yet-completed future |
16 | Future(/* #[pin] */ Fut), |
17 | /// The output of the completed future |
18 | Done(Fut::Output), |
19 | /// The empty variant after the result of a [`MaybeDone`] has been |
20 | /// taken using the [`take_output`](MaybeDone::take_output) method. |
21 | Gone, |
22 | } |
23 | |
24 | impl<Fut: Future + Unpin> Unpin for MaybeDone<Fut> {} |
25 | |
26 | /// Wraps a future into a `MaybeDone` |
27 | /// |
28 | /// # Examples |
29 | /// |
30 | /// ``` |
31 | /// # futures::executor::block_on(async { |
32 | /// use futures::future; |
33 | /// use futures::pin_mut; |
34 | /// |
35 | /// let future = future::maybe_done(async { 5 }); |
36 | /// pin_mut!(future); |
37 | /// assert_eq!(future.as_mut().take_output(), None); |
38 | /// let () = future.as_mut().await; |
39 | /// assert_eq!(future.as_mut().take_output(), Some(5)); |
40 | /// assert_eq!(future.as_mut().take_output(), None); |
41 | /// # }); |
42 | /// ``` |
43 | pub fn maybe_done<Fut: Future>(future: Fut) -> MaybeDone<Fut> { |
44 | assert_future::<(), _>(MaybeDone::Future(future)) |
45 | } |
46 | |
47 | impl<Fut: Future> MaybeDone<Fut> { |
48 | /// Returns an [`Option`] containing a mutable reference to the output of the future. |
49 | /// The output of this method will be [`Some`] if and only if the inner |
50 | /// future has been completed and [`take_output`](MaybeDone::take_output) |
51 | /// has not yet been called. |
52 | #[inline ] |
53 | pub fn output_mut(self: Pin<&mut Self>) -> Option<&mut Fut::Output> { |
54 | unsafe { |
55 | match self.get_unchecked_mut() { |
56 | MaybeDone::Done(res) => Some(res), |
57 | _ => None, |
58 | } |
59 | } |
60 | } |
61 | |
62 | /// Attempt to take the output of a `MaybeDone` without driving it |
63 | /// towards completion. |
64 | #[inline ] |
65 | pub fn take_output(self: Pin<&mut Self>) -> Option<Fut::Output> { |
66 | match &*self { |
67 | Self::Done(_) => {} |
68 | Self::Future(_) | Self::Gone => return None, |
69 | } |
70 | unsafe { |
71 | match mem::replace(self.get_unchecked_mut(), Self::Gone) { |
72 | MaybeDone::Done(output) => Some(output), |
73 | _ => unreachable!(), |
74 | } |
75 | } |
76 | } |
77 | } |
78 | |
79 | impl<Fut: Future> FusedFuture for MaybeDone<Fut> { |
80 | fn is_terminated(&self) -> bool { |
81 | match self { |
82 | Self::Future(_) => false, |
83 | Self::Done(_) | Self::Gone => true, |
84 | } |
85 | } |
86 | } |
87 | |
88 | impl<Fut: Future> Future for MaybeDone<Fut> { |
89 | type Output = (); |
90 | |
91 | fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> { |
92 | unsafe { |
93 | match self.as_mut().get_unchecked_mut() { |
94 | MaybeDone::Future(f) => { |
95 | let res = ready!(Pin::new_unchecked(f).poll(cx)); |
96 | self.set(Self::Done(res)); |
97 | } |
98 | MaybeDone::Done(_) => {} |
99 | MaybeDone::Gone => panic!("MaybeDone polled after value taken" ), |
100 | } |
101 | } |
102 | Poll::Ready(()) |
103 | } |
104 | } |
105 | |