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}