windows_future/
future.rs

1use super::*;
2use std::future::{Future, IntoFuture};
3use std::pin::Pin;
4use std::sync::{Arc, Mutex};
5use std::task::{Context, Poll, Waker};
6
7// The `AsyncFuture` is needed to store some extra state needed to keep async execution up to date with possible changes
8// to Rust execution context. Each async type implements `IntoFuture` rather than implementing `Future` directly so that
9// this adapter may be used.
10pub struct AsyncFuture<A: Async> {
11    // Represents the async execution and provides the virtual methods for setting up a `Completed` handler and
12    // calling `GetResults` when execution is completed.
13    inner: A,
14
15    // Provides the `Status` virtual method and saves repeated calls to `QueryInterface` during polling.
16    status: IAsyncInfo,
17
18    // A shared waker is needed to keep the `Completed` handler updated.
19    // - `Option` is used to avoid allocations for async objects that have already completed.
20    // - `Arc` is used to share the `Waker` with the `Completed` handler and potentially replace the `Waker`
21    //   since we don't have the ability to replace the `Completed` handler itself.
22    // - `Mutex` is used to synchronize replacing the `Waker` across threads.
23    waker: Option<Arc<Mutex<Waker>>>,
24}
25
26impl<A: Async> AsyncFuture<A> {
27    fn new(inner: A) -> Self {
28        Self {
29            // All four async interfaces implement `IAsyncInfo` so this `cast` will always succeed.
30            status: inner.cast().unwrap(),
31            inner,
32            waker: None,
33        }
34    }
35}
36
37unsafe impl<A: Async> Send for AsyncFuture<A> {}
38unsafe impl<A: Async> Sync for AsyncFuture<A> {}
39impl<A: Async> Unpin for AsyncFuture<A> {}
40
41impl<A: Async> Future for AsyncFuture<A> {
42    type Output = Result<A::Output>;
43
44    fn poll(mut self: Pin<&mut Self>, cx: &mut Context) -> Poll<Self::Output> {
45        // A status of `Started` just means async execution is still in flight. Since WinRT async is always
46        // "hot start", if its not `Started` then its ready for us to call `GetResults` so we can skip all of
47        // the remaining set up.
48        if self.status.Status()? != AsyncStatus::Started {
49            return Poll::Ready(self.inner.get_results());
50        }
51
52        if let Some(shared_waker) = &self.waker {
53            // We have a shared waker which means we're either getting polled again or been transferred to
54            // another execution context. As we can't tell the difference, we need to update the shared waker
55            // to make sure we've got the "current" waker.
56            let mut guard = shared_waker.lock().unwrap();
57            guard.clone_from(cx.waker());
58
59            // It may be possible that the `Completed` handler acquired the lock and signaled the old waker
60            // before we managed to acquire the lock to update it with the current waker. We check the status
61            // again here just in case this happens.
62            if self.status.Status()? != AsyncStatus::Started {
63                return Poll::Ready(self.inner.get_results());
64            }
65        } else {
66            // If we don't have a saved waker it means this is the first time we're getting polled and should
67            // create the shared waker and set up a `Completed` handler.
68            let shared_waker = Arc::new(Mutex::new(cx.waker().clone()));
69            self.waker = Some(shared_waker.clone());
70
71            // Note that the handler can only be set once, which is why we need a shared waker in the first
72            // place. On the other hand, the handler will get called even if async execution has already
73            // completed, so we can just return `Pending` after setting the Completed handler.
74            self.inner.set_completed(move |_| {
75                shared_waker.lock().unwrap().wake_by_ref();
76            })?;
77        };
78
79        Poll::Pending
80    }
81}
82
83//
84// The four `IntoFuture` trait implementations.
85//
86
87impl IntoFuture for IAsyncAction {
88    type Output = Result<()>;
89    type IntoFuture = AsyncFuture<Self>;
90
91    fn into_future(self) -> Self::IntoFuture {
92        AsyncFuture::new(self)
93    }
94}
95
96impl<T: RuntimeType> IntoFuture for IAsyncOperation<T> {
97    type Output = Result<T>;
98    type IntoFuture = AsyncFuture<Self>;
99
100    fn into_future(self) -> Self::IntoFuture {
101        AsyncFuture::new(self)
102    }
103}
104
105impl<P: RuntimeType> IntoFuture for IAsyncActionWithProgress<P> {
106    type Output = Result<()>;
107    type IntoFuture = AsyncFuture<Self>;
108
109    fn into_future(self) -> Self::IntoFuture {
110        AsyncFuture::new(self)
111    }
112}
113
114impl<T: RuntimeType, P: RuntimeType> IntoFuture for IAsyncOperationWithProgress<T, P> {
115    type Output = Result<T>;
116    type IntoFuture = AsyncFuture<Self>;
117
118    fn into_future(self) -> Self::IntoFuture {
119        AsyncFuture::new(self)
120    }
121}