Skip to content

Commit 2030b20

Browse files
authored
Update windows-future with join and when functions (#3708)
1 parent 2d39427 commit 2030b20

File tree

23 files changed

+437
-243
lines changed

23 files changed

+437
-243
lines changed

crates/libs/future/readme.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,12 +20,12 @@ use windows_future::*;
2020

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

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

30-
assert_eq!(ready.get().unwrap(), 456);
30+
assert_eq!(ready.join().unwrap(), 456);
3131
```

crates/libs/future/src/async.rs

Lines changed: 169 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,169 @@
1+
use super::*;
2+
3+
// An `Async` represents a WinRT async execution object or type. There are precisely four such types:
4+
// - IAsyncAction
5+
// - IAsyncActionWithProgress
6+
// - IAsyncOperation
7+
// - IAsyncOperationWithProgress
8+
//
9+
// All four implementations are provided here and there is thus no need to implement this trait.
10+
// This trait provides an abstraction over the relevant differences so that the various async
11+
// capabilities in this crate can be reused for all implementations.
12+
pub trait Async: Interface {
13+
// The type of value produced on completion.
14+
type Output: Clone;
15+
16+
// The type of the delegate use for completion notification.
17+
type CompletedHandler: Interface;
18+
19+
// Sets the handler or callback to invoke when execution completes. This handler can only be set once.
20+
fn set_completed<F: Fn(&Self) + Send + 'static>(&self, handler: F) -> Result<()>;
21+
22+
// Calls the given handler with the current object and status.
23+
#[cfg(feature = "std")]
24+
fn invoke_completed(&self, handler: &Self::CompletedHandler, status: AsyncStatus);
25+
26+
// Returns the value produced on completion. This should only be called when execution completes.
27+
fn get_results(&self) -> Result<Self::Output>;
28+
29+
// Gets the current status of async execution. This calls `QueryInterface` so should be used sparingly.
30+
fn status(&self) -> Result<AsyncStatus>;
31+
32+
// Waits for the async execution to finish and then returns the results.
33+
fn join(&self) -> Result<Self::Output> {
34+
if self.status()? == AsyncStatus::Started {
35+
let (_waiter, signaler) = Waiter::new()?;
36+
self.set_completed(move |_| {
37+
// This is safe because the waiter will only be dropped after being signaled.
38+
unsafe {
39+
signaler.signal();
40+
}
41+
})?;
42+
}
43+
self.get_results()
44+
}
45+
46+
// Calls `op(result)` when async execution completes.
47+
fn when<F>(&self, op: F) -> Result<()>
48+
where
49+
F: FnOnce(Result<Self::Output>) + Send + 'static,
50+
{
51+
if self.status()? == AsyncStatus::Started {
52+
// The `set_completed` closure is guaranteed to only be called once, like `FnOnce`, by the async pattern,
53+
// but Rust doesn't know that so `RefCell` is used to pass `op` in to the closure.
54+
let op = core::cell::RefCell::new(Some(op));
55+
self.set_completed(move |sender| {
56+
if let Some(op) = op.take() {
57+
op(sender.get_results());
58+
}
59+
})?;
60+
} else {
61+
op(self.get_results());
62+
}
63+
Ok(())
64+
}
65+
}
66+
67+
impl Async for IAsyncAction {
68+
type Output = ();
69+
type CompletedHandler = AsyncActionCompletedHandler;
70+
71+
fn set_completed<F: Fn(&Self) + Send + 'static>(&self, handler: F) -> Result<()> {
72+
self.SetCompleted(&AsyncActionCompletedHandler::new(move |sender, _| {
73+
handler(sender.ok()?);
74+
Ok(())
75+
}))
76+
}
77+
78+
#[cfg(feature = "std")]
79+
fn invoke_completed(&self, handler: &Self::CompletedHandler, status: AsyncStatus) {
80+
_ = handler.Invoke(self, status);
81+
}
82+
83+
fn get_results(&self) -> Result<Self::Output> {
84+
self.GetResults()
85+
}
86+
87+
fn status(&self) -> Result<AsyncStatus> {
88+
self.Status()
89+
}
90+
}
91+
92+
impl<T: RuntimeType> Async for IAsyncOperation<T> {
93+
type Output = T;
94+
type CompletedHandler = AsyncOperationCompletedHandler<T>;
95+
96+
fn set_completed<F: Fn(&Self) + Send + 'static>(&self, handler: F) -> Result<()> {
97+
self.SetCompleted(&AsyncOperationCompletedHandler::new(move |sender, _| {
98+
handler(sender.ok()?);
99+
Ok(())
100+
}))
101+
}
102+
103+
#[cfg(feature = "std")]
104+
fn invoke_completed(&self, handler: &Self::CompletedHandler, status: AsyncStatus) {
105+
_ = handler.Invoke(self, status);
106+
}
107+
108+
fn get_results(&self) -> Result<Self::Output> {
109+
self.GetResults()
110+
}
111+
112+
fn status(&self) -> Result<AsyncStatus> {
113+
self.Status()
114+
}
115+
}
116+
117+
impl<P: RuntimeType> Async for IAsyncActionWithProgress<P> {
118+
type Output = ();
119+
type CompletedHandler = AsyncActionWithProgressCompletedHandler<P>;
120+
121+
fn set_completed<F: Fn(&Self) + Send + 'static>(&self, handler: F) -> Result<()> {
122+
self.SetCompleted(&AsyncActionWithProgressCompletedHandler::new(
123+
move |sender, _| {
124+
handler(sender.ok()?);
125+
Ok(())
126+
},
127+
))
128+
}
129+
130+
#[cfg(feature = "std")]
131+
fn invoke_completed(&self, handler: &Self::CompletedHandler, status: AsyncStatus) {
132+
_ = handler.Invoke(self, status);
133+
}
134+
135+
fn get_results(&self) -> Result<Self::Output> {
136+
self.GetResults()
137+
}
138+
139+
fn status(&self) -> Result<AsyncStatus> {
140+
self.Status()
141+
}
142+
}
143+
144+
impl<T: RuntimeType, P: RuntimeType> Async for IAsyncOperationWithProgress<T, P> {
145+
type Output = T;
146+
type CompletedHandler = AsyncOperationWithProgressCompletedHandler<T, P>;
147+
148+
fn set_completed<F: Fn(&Self) + Send + 'static>(&self, handler: F) -> Result<()> {
149+
self.SetCompleted(&AsyncOperationWithProgressCompletedHandler::new(
150+
move |sender, _| {
151+
handler(sender.ok()?);
152+
Ok(())
153+
},
154+
))
155+
}
156+
157+
#[cfg(feature = "std")]
158+
fn invoke_completed(&self, handler: &Self::CompletedHandler, status: AsyncStatus) {
159+
_ = handler.Invoke(self, status);
160+
}
161+
162+
fn get_results(&self) -> Result<Self::Output> {
163+
self.GetResults()
164+
}
165+
166+
fn status(&self) -> Result<AsyncStatus> {
167+
self.Status()
168+
}
169+
}

crates/libs/future/src/future.rs

Lines changed: 1 addition & 115 deletions
Original file line numberDiff line numberDiff line change
@@ -4,32 +4,6 @@ use std::pin::Pin;
44
use std::sync::{Arc, Mutex};
55
use std::task::{Context, Poll, Waker};
66

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.
16-
pub 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, handler: &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-
337
// The `AsyncFuture` is needed to store some extra state needed to keep async execution up to date with possible changes
348
// to Rust execution context. Each async type implements `IntoFuture` rather than implementing `Future` directly so that
359
// this adapter may be used.
@@ -97,7 +71,7 @@ impl<A: Async> Future for AsyncFuture<A> {
9771
// Note that the handler can only be set once, which is why we need a shared waker in the first
9872
// place. On the other hand, the handler will get called even if async execution has already
9973
// completed, so we can just return `Pending` after setting the Completed handler.
100-
self.inner.set_completed(move || {
74+
self.inner.set_completed(move |_| {
10175
shared_waker.lock().unwrap().wake_by_ref();
10276
})?;
10377
};
@@ -106,94 +80,6 @@ impl<A: Async> Future for AsyncFuture<A> {
10680
}
10781
}
10882

109-
//
110-
// The four `Async` trait implementations.
111-
//
112-
113-
impl 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-
133-
impl<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-
153-
impl<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-
175-
impl<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-
19783
//
19884
// The four `IntoFuture` trait implementations.
19985
//

crates/libs/future/src/get.rs

Lines changed: 0 additions & 73 deletions
This file was deleted.

0 commit comments

Comments
 (0)