use super::*; use std::future::{Future, IntoFuture}; use std::pin::Pin; use std::sync::{Arc, Mutex}; use std::task::{Context, Poll, Waker}; // The `AsyncFuture` is needed to store some extra state needed to keep async execution up to date with possible changes // to Rust execution context. Each async type implements `IntoFuture` rather than implementing `Future` directly so that // this adapter may be used. pub struct AsyncFuture { // Represents the async execution and provides the virtual methods for setting up a `Completed` handler and // calling `GetResults` when execution is completed. inner: A, // Provides the `Status` virtual method and saves repeated calls to `QueryInterface` during polling. status: IAsyncInfo, // A shared waker is needed to keep the `Completed` handler updated. // - `Option` is used to avoid allocations for async objects that have already completed. // - `Arc` is used to share the `Waker` with the `Completed` handler and potentially replace the `Waker` // since we don't have the ability to replace the `Completed` handler itself. // - `Mutex` is used to synchronize replacing the `Waker` across threads. waker: Option>>, } impl AsyncFuture { fn new(inner: A) -> Self { Self { // All four async interfaces implement `IAsyncInfo` so this `cast` will always succeed. status: inner.cast().unwrap(), inner, waker: None, } } } unsafe impl Send for AsyncFuture {} unsafe impl Sync for AsyncFuture {} impl Unpin for AsyncFuture {} impl Future for AsyncFuture { type Output = Result; fn poll(mut self: Pin<&mut Self>, cx: &mut Context) -> Poll { // A status of `Started` just means async execution is still in flight. Since WinRT async is always // "hot start", if its not `Started` then its ready for us to call `GetResults` so we can skip all of // the remaining set up. if self.status.Status()? != AsyncStatus::Started { return Poll::Ready(self.inner.get_results()); } if let Some(shared_waker) = &self.waker { // We have a shared waker which means we're either getting polled again or been transferred to // another execution context. As we can't tell the difference, we need to update the shared waker // to make sure we've got the "current" waker. let mut guard = shared_waker.lock().unwrap(); guard.clone_from(cx.waker()); // It may be possible that the `Completed` handler acquired the lock and signaled the old waker // before we managed to acquire the lock to update it with the current waker. We check the status // again here just in case this happens. if self.status.Status()? != AsyncStatus::Started { return Poll::Ready(self.inner.get_results()); } } else { // If we don't have a saved waker it means this is the first time we're getting polled and should // create the shared waker and set up a `Completed` handler. let shared_waker = Arc::new(Mutex::new(cx.waker().clone())); self.waker = Some(shared_waker.clone()); // Note that the handler can only be set once, which is why we need a shared waker in the first // place. On the other hand, the handler will get called even if async execution has already // completed, so we can just return `Pending` after setting the Completed handler. self.inner.set_completed(move |_| { shared_waker.lock().unwrap().wake_by_ref(); })?; }; Poll::Pending } } // // The four `IntoFuture` trait implementations. // impl IntoFuture for IAsyncAction { type Output = Result<()>; type IntoFuture = AsyncFuture; fn into_future(self) -> Self::IntoFuture { AsyncFuture::new(self) } } impl IntoFuture for IAsyncOperation { type Output = Result; type IntoFuture = AsyncFuture; fn into_future(self) -> Self::IntoFuture { AsyncFuture::new(self) } } impl IntoFuture for IAsyncActionWithProgress

{ type Output = Result<()>; type IntoFuture = AsyncFuture; fn into_future(self) -> Self::IntoFuture { AsyncFuture::new(self) } } impl IntoFuture for IAsyncOperationWithProgress { type Output = Result; type IntoFuture = AsyncFuture; fn into_future(self) -> Self::IntoFuture { AsyncFuture::new(self) } }