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// An `Async` represents a WinRT async execution object or type. There are precisely four such types:
8// - IAsyncAction
9// - IAsyncActionWithProgress
10// - IAsyncOperation
11// - IAsyncOperationWithProgress
12//
13// All four implementations are provided here and there is thus no need to implement this trait.
14// This trait provides an abstraction over the relevant differences so that the `AsyncFuture`
15// implementation below can be reused for all of them.
16pub trait Async: Interface {
17    // The type of value produced on completion.
18    type Output: Clone;
19
20    // The type of the delegate use for completion notification.
21    type CompletedHandler: Interface;
22
23    // Sets the handler or callback to invoke when execution completes. This handler can only be set once.
24    fn set_completed<F: Fn() + Send + 'static>(&self, handler: F) -> Result<()>;
25
26    // Calls the given handler with the current object and status.
27    fn invoke_completed(&self, hander: &Self::CompletedHandler, status: AsyncStatus);
28
29    // Returns the value produced on completion. This should only be called when execution completes.
30    fn get_results(&self) -> Result<Self::Output>;
31}
32
33// The `AsyncFuture` is needed to store some extra state needed to keep async execution up to date with possible changes
34// to Rust execution context. Each async type implements `IntoFuture` rather than implementing `Future` directly so that
35// this adapter may be used.
36pub struct AsyncFuture<A: Async> {
37    // Represents the async execution and provides the virtual methods for setting up a `Completed` handler and
38    // calling `GetResults` when execution is completed.
39    inner: A,
40
41    // Provides the `Status` virtual method and saves repeated calls to `QueryInterface` during polling.
42    status: IAsyncInfo,
43
44    // A shared waker is needed to keep the `Completed` handler updated.
45    // - `Option` is used to avoid allocations for async objects that have already completed.
46    // - `Arc` is used to share the `Waker` with the `Completed` handler and potentially replace the `Waker`
47    //   since we don't have the ability to replace the `Completed` handler itself.
48    // - `Mutex` is used to synchronize replacing the `Waker` across threads.
49    waker: Option<Arc<Mutex<Waker>>>,
50}
51
52impl<A: Async> AsyncFuture<A> {
53    fn new(inner: A) -> Self {
54        Self {
55            // All four async interfaces implement `IAsyncInfo` so this `cast` will always succeed.
56            status: inner.cast().unwrap(),
57            inner,
58            waker: None,
59        }
60    }
61}
62
63unsafe impl<A: Async> Send for AsyncFuture<A> {}
64unsafe impl<A: Async> Sync for AsyncFuture<A> {}
65impl<A: Async> Unpin for AsyncFuture<A> {}
66
67impl<A: Async> Future for AsyncFuture<A> {
68    type Output = Result<A::Output>;
69
70    fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
71        // A status of `Started` just means async execution is still in flight. Since WinRT async is always
72        // "hot start", if its not `Started` then its ready for us to call `GetResults` so we can skip all of
73        // the remaining set up.
74        if self.status.Status()? != AsyncStatus::Started {
75            return Poll::Ready(self.inner.get_results());
76        }
77
78        if let Some(shared_waker) = &self.waker {
79            // We have a shared waker which means we're either getting polled again or been transfered to
80            // another execution context. As we can't tell the difference, we need to update the shared waker
81            // to make sure we've got the "current" waker.
82            let mut guard = shared_waker.lock().unwrap();
83            guard.clone_from(cx.waker());
84
85            // It may be possible that the `Completed` handler acquired the lock and signaled the old waker
86            // before we managed to acquire the lock to update it with the current waker. We check the status
87            // again here just in case this happens.
88            if self.status.Status()? != AsyncStatus::Started {
89                return Poll::Ready(self.inner.get_results());
90            }
91        } else {
92            // If we don't have a saved waker it means this is the first time we're getting polled and should
93            // create the shared waker and set up a `Completed` handler.
94            let shared_waker = Arc::new(Mutex::new(cx.waker().clone()));
95            self.waker = Some(shared_waker.clone());
96
97            // Note that the handler can only be set once, which is why we need a shared waker in the first
98            // place. On the other hand, the handler will get called even if async execution has already
99            // completed, so we can just return `Pending` after setting the Completed handler.
100            self.inner.set_completed(move || {
101                shared_waker.lock().unwrap().wake_by_ref();
102            })?;
103        };
104
105        Poll::Pending
106    }
107}
108
109//
110// The four `Async` trait implementations.
111//
112
113impl Async for IAsyncAction {
114    type Output = ();
115    type CompletedHandler = AsyncActionCompletedHandler;
116
117    fn set_completed<F: Fn() + Send + 'static>(&self, handler: F) -> Result<()> {
118        self.SetCompleted(&AsyncActionCompletedHandler::new(move |_, _| {
119            handler();
120            Ok(())
121        }))
122    }
123
124    fn invoke_completed(&self, handler: &Self::CompletedHandler, status: AsyncStatus) {
125        _ = handler.Invoke(self, status);
126    }
127
128    fn get_results(&self) -> Result<Self::Output> {
129        self.GetResults()
130    }
131}
132
133impl<T: RuntimeType> Async for IAsyncOperation<T> {
134    type Output = T;
135    type CompletedHandler = AsyncOperationCompletedHandler<T>;
136
137    fn set_completed<F: Fn() + Send + 'static>(&self, handler: F) -> Result<()> {
138        self.SetCompleted(&AsyncOperationCompletedHandler::new(move |_, _| {
139            handler();
140            Ok(())
141        }))
142    }
143
144    fn invoke_completed(&self, handler: &Self::CompletedHandler, status: AsyncStatus) {
145        _ = handler.Invoke(self, status);
146    }
147
148    fn get_results(&self) -> Result<Self::Output> {
149        self.GetResults()
150    }
151}
152
153impl<P: RuntimeType> Async for IAsyncActionWithProgress<P> {
154    type Output = ();
155    type CompletedHandler = AsyncActionWithProgressCompletedHandler<P>;
156
157    fn set_completed<F: Fn() + Send + 'static>(&self, handler: F) -> Result<()> {
158        self.SetCompleted(&AsyncActionWithProgressCompletedHandler::new(
159            move |_, _| {
160                handler();
161                Ok(())
162            },
163        ))
164    }
165
166    fn invoke_completed(&self, handler: &Self::CompletedHandler, status: AsyncStatus) {
167        _ = handler.Invoke(self, status);
168    }
169
170    fn get_results(&self) -> Result<Self::Output> {
171        self.GetResults()
172    }
173}
174
175impl<T: RuntimeType, P: RuntimeType> Async for IAsyncOperationWithProgress<T, P> {
176    type Output = T;
177    type CompletedHandler = AsyncOperationWithProgressCompletedHandler<T, P>;
178
179    fn set_completed<F: Fn() + Send + 'static>(&self, handler: F) -> Result<()> {
180        self.SetCompleted(&AsyncOperationWithProgressCompletedHandler::new(
181            move |_, _| {
182                handler();
183                Ok(())
184            },
185        ))
186    }
187
188    fn invoke_completed(&self, handler: &Self::CompletedHandler, status: AsyncStatus) {
189        _ = handler.Invoke(self, status);
190    }
191
192    fn get_results(&self) -> Result<Self::Output> {
193        self.GetResults()
194    }
195}
196
197//
198// The four `IntoFuture` trait implementations.
199//
200
201impl IntoFuture for IAsyncAction {
202    type Output = Result<()>;
203    type IntoFuture = AsyncFuture<Self>;
204
205    fn into_future(self) -> Self::IntoFuture {
206        AsyncFuture::new(self)
207    }
208}
209
210impl<T: RuntimeType> IntoFuture for IAsyncOperation<T> {
211    type Output = Result<T>;
212    type IntoFuture = AsyncFuture<Self>;
213
214    fn into_future(self) -> Self::IntoFuture {
215        AsyncFuture::new(self)
216    }
217}
218
219impl<P: RuntimeType> IntoFuture for IAsyncActionWithProgress<P> {
220    type Output = Result<()>;
221    type IntoFuture = AsyncFuture<Self>;
222
223    fn into_future(self) -> Self::IntoFuture {
224        AsyncFuture::new(self)
225    }
226}
227
228impl<T: RuntimeType, P: RuntimeType> IntoFuture for IAsyncOperationWithProgress<T, P> {
229    type Output = Result<T>;
230    type IntoFuture = AsyncFuture<Self>;
231
232    fn into_future(self) -> Self::IntoFuture {
233        AsyncFuture::new(self)
234    }
235}