Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions crates/libs/future/readme.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,12 +20,12 @@ use windows_future::*;

// This result will be available immediately.
let ready = IAsyncOperation::ready(Ok(123));
assert_eq!(ready.get().unwrap(), 123);
assert_eq!(ready.join().unwrap(), 123);

let ready = IAsyncOperation::spawn(|| {
// Some lengthy operation goes here...
Ok(456)
});

assert_eq!(ready.get().unwrap(), 456);
assert_eq!(ready.join().unwrap(), 456);
```
169 changes: 169 additions & 0 deletions crates/libs/future/src/async.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,169 @@
use super::*;

// An `Async` represents a WinRT async execution object or type. There are precisely four such types:
// - IAsyncAction
// - IAsyncActionWithProgress
// - IAsyncOperation
// - IAsyncOperationWithProgress
//
// All four implementations are provided here and there is thus no need to implement this trait.
// This trait provides an abstraction over the relevant differences so that the various async
// capabilities in this crate can be reused for all implementations.
pub trait Async: Interface {
// The type of value produced on completion.
type Output: Clone;

// The type of the delegate use for completion notification.
type CompletedHandler: Interface;

// Sets the handler or callback to invoke when execution completes. This handler can only be set once.
fn set_completed<F: Fn(&Self) + Send + 'static>(&self, handler: F) -> Result<()>;

// Calls the given handler with the current object and status.
#[cfg(feature = "std")]
fn invoke_completed(&self, handler: &Self::CompletedHandler, status: AsyncStatus);

// Returns the value produced on completion. This should only be called when execution completes.
fn get_results(&self) -> Result<Self::Output>;

// Gets the current status of async execution. This calls `QueryInterface` so should be used sparingly.
fn status(&self) -> Result<AsyncStatus>;

// Waits for the async execution to finish and then returns the results.
fn join(&self) -> Result<Self::Output> {
if self.status()? == AsyncStatus::Started {
let (_waiter, signaler) = Waiter::new()?;
self.set_completed(move |_| {
// This is safe because the waiter will only be dropped after being signaled.
unsafe {
signaler.signal();
}
})?;
}
self.get_results()
}

// Calls `op(result)` when async execution completes.
fn when<F>(&self, op: F) -> Result<()>
where
F: FnOnce(Result<Self::Output>) + Send + 'static,
{
if self.status()? == AsyncStatus::Started {
// The `set_completed` closure is guaranteed to only be called once, like `FnOnce`, by the async pattern,
// but Rust doesn't know that so `RefCell` is used to pass `op` in to the closure.
let op = core::cell::RefCell::new(Some(op));
self.set_completed(move |sender| {
if let Some(op) = op.take() {
op(sender.get_results());
}
})?;
} else {
op(self.get_results());
}
Ok(())
}
}

impl Async for IAsyncAction {
type Output = ();
type CompletedHandler = AsyncActionCompletedHandler;

fn set_completed<F: Fn(&Self) + Send + 'static>(&self, handler: F) -> Result<()> {
self.SetCompleted(&AsyncActionCompletedHandler::new(move |sender, _| {
handler(sender.ok()?);
Ok(())
}))
}

#[cfg(feature = "std")]
fn invoke_completed(&self, handler: &Self::CompletedHandler, status: AsyncStatus) {
_ = handler.Invoke(self, status);
}

fn get_results(&self) -> Result<Self::Output> {
self.GetResults()
}

fn status(&self) -> Result<AsyncStatus> {
self.Status()
}
}

impl<T: RuntimeType> Async for IAsyncOperation<T> {
type Output = T;
type CompletedHandler = AsyncOperationCompletedHandler<T>;

fn set_completed<F: Fn(&Self) + Send + 'static>(&self, handler: F) -> Result<()> {
self.SetCompleted(&AsyncOperationCompletedHandler::new(move |sender, _| {
handler(sender.ok()?);
Ok(())
}))
}

#[cfg(feature = "std")]
fn invoke_completed(&self, handler: &Self::CompletedHandler, status: AsyncStatus) {
_ = handler.Invoke(self, status);
}

fn get_results(&self) -> Result<Self::Output> {
self.GetResults()
}

fn status(&self) -> Result<AsyncStatus> {
self.Status()
}
}

impl<P: RuntimeType> Async for IAsyncActionWithProgress<P> {
type Output = ();
type CompletedHandler = AsyncActionWithProgressCompletedHandler<P>;

fn set_completed<F: Fn(&Self) + Send + 'static>(&self, handler: F) -> Result<()> {
self.SetCompleted(&AsyncActionWithProgressCompletedHandler::new(
move |sender, _| {
handler(sender.ok()?);
Ok(())
},
))
}

#[cfg(feature = "std")]
fn invoke_completed(&self, handler: &Self::CompletedHandler, status: AsyncStatus) {
_ = handler.Invoke(self, status);
}

fn get_results(&self) -> Result<Self::Output> {
self.GetResults()
}

fn status(&self) -> Result<AsyncStatus> {
self.Status()
}
}

impl<T: RuntimeType, P: RuntimeType> Async for IAsyncOperationWithProgress<T, P> {
type Output = T;
type CompletedHandler = AsyncOperationWithProgressCompletedHandler<T, P>;

fn set_completed<F: Fn(&Self) + Send + 'static>(&self, handler: F) -> Result<()> {
self.SetCompleted(&AsyncOperationWithProgressCompletedHandler::new(
move |sender, _| {
handler(sender.ok()?);
Ok(())
},
))
}

#[cfg(feature = "std")]
fn invoke_completed(&self, handler: &Self::CompletedHandler, status: AsyncStatus) {
_ = handler.Invoke(self, status);
}

fn get_results(&self) -> Result<Self::Output> {
self.GetResults()
}

fn status(&self) -> Result<AsyncStatus> {
self.Status()
}
}
116 changes: 1 addition & 115 deletions crates/libs/future/src/future.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,32 +4,6 @@ use std::pin::Pin;
use std::sync::{Arc, Mutex};
use std::task::{Context, Poll, Waker};

// An `Async` represents a WinRT async execution object or type. There are precisely four such types:
// - IAsyncAction
// - IAsyncActionWithProgress
// - IAsyncOperation
// - IAsyncOperationWithProgress
//
// All four implementations are provided here and there is thus no need to implement this trait.
// This trait provides an abstraction over the relevant differences so that the `AsyncFuture`
// implementation below can be reused for all of them.
pub trait Async: Interface {
// The type of value produced on completion.
type Output: Clone;

// The type of the delegate use for completion notification.
type CompletedHandler: Interface;

// Sets the handler or callback to invoke when execution completes. This handler can only be set once.
fn set_completed<F: Fn() + Send + 'static>(&self, handler: F) -> Result<()>;

// Calls the given handler with the current object and status.
fn invoke_completed(&self, handler: &Self::CompletedHandler, status: AsyncStatus);

// Returns the value produced on completion. This should only be called when execution completes.
fn get_results(&self) -> Result<Self::Output>;
}

// 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.
Expand Down Expand Up @@ -97,7 +71,7 @@ impl<A: Async> Future for AsyncFuture<A> {
// 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 || {
self.inner.set_completed(move |_| {
shared_waker.lock().unwrap().wake_by_ref();
})?;
};
Expand All @@ -106,94 +80,6 @@ impl<A: Async> Future for AsyncFuture<A> {
}
}

//
// The four `Async` trait implementations.
//

impl Async for IAsyncAction {
type Output = ();
type CompletedHandler = AsyncActionCompletedHandler;

fn set_completed<F: Fn() + Send + 'static>(&self, handler: F) -> Result<()> {
self.SetCompleted(&AsyncActionCompletedHandler::new(move |_, _| {
handler();
Ok(())
}))
}

fn invoke_completed(&self, handler: &Self::CompletedHandler, status: AsyncStatus) {
_ = handler.Invoke(self, status);
}

fn get_results(&self) -> Result<Self::Output> {
self.GetResults()
}
}

impl<T: RuntimeType> Async for IAsyncOperation<T> {
type Output = T;
type CompletedHandler = AsyncOperationCompletedHandler<T>;

fn set_completed<F: Fn() + Send + 'static>(&self, handler: F) -> Result<()> {
self.SetCompleted(&AsyncOperationCompletedHandler::new(move |_, _| {
handler();
Ok(())
}))
}

fn invoke_completed(&self, handler: &Self::CompletedHandler, status: AsyncStatus) {
_ = handler.Invoke(self, status);
}

fn get_results(&self) -> Result<Self::Output> {
self.GetResults()
}
}

impl<P: RuntimeType> Async for IAsyncActionWithProgress<P> {
type Output = ();
type CompletedHandler = AsyncActionWithProgressCompletedHandler<P>;

fn set_completed<F: Fn() + Send + 'static>(&self, handler: F) -> Result<()> {
self.SetCompleted(&AsyncActionWithProgressCompletedHandler::new(
move |_, _| {
handler();
Ok(())
},
))
}

fn invoke_completed(&self, handler: &Self::CompletedHandler, status: AsyncStatus) {
_ = handler.Invoke(self, status);
}

fn get_results(&self) -> Result<Self::Output> {
self.GetResults()
}
}

impl<T: RuntimeType, P: RuntimeType> Async for IAsyncOperationWithProgress<T, P> {
type Output = T;
type CompletedHandler = AsyncOperationWithProgressCompletedHandler<T, P>;

fn set_completed<F: Fn() + Send + 'static>(&self, handler: F) -> Result<()> {
self.SetCompleted(&AsyncOperationWithProgressCompletedHandler::new(
move |_, _| {
handler();
Ok(())
},
))
}

fn invoke_completed(&self, handler: &Self::CompletedHandler, status: AsyncStatus) {
_ = handler.Invoke(self, status);
}

fn get_results(&self) -> Result<Self::Output> {
self.GetResults()
}
}

//
// The four `IntoFuture` trait implementations.
//
Expand Down
73 changes: 0 additions & 73 deletions crates/libs/future/src/get.rs

This file was deleted.

Loading
Loading