diff --git a/crates/libs/future/readme.md b/crates/libs/future/readme.md index f44f75dc13..83dba832fd 100644 --- a/crates/libs/future/readme.md +++ b/crates/libs/future/readme.md @@ -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); ``` diff --git a/crates/libs/future/src/async.rs b/crates/libs/future/src/async.rs new file mode 100644 index 0000000000..d6a5bf50e1 --- /dev/null +++ b/crates/libs/future/src/async.rs @@ -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(&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; + + // Gets the current status of async execution. This calls `QueryInterface` so should be used sparingly. + fn status(&self) -> Result; + + // Waits for the async execution to finish and then returns the results. + fn join(&self) -> Result { + 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(&self, op: F) -> Result<()> + where + F: FnOnce(Result) + 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(&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.GetResults() + } + + fn status(&self) -> Result { + self.Status() + } +} + +impl Async for IAsyncOperation { + type Output = T; + type CompletedHandler = AsyncOperationCompletedHandler; + + fn set_completed(&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.GetResults() + } + + fn status(&self) -> Result { + self.Status() + } +} + +impl Async for IAsyncActionWithProgress

{ + type Output = (); + type CompletedHandler = AsyncActionWithProgressCompletedHandler

; + + fn set_completed(&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.GetResults() + } + + fn status(&self) -> Result { + self.Status() + } +} + +impl Async for IAsyncOperationWithProgress { + type Output = T; + type CompletedHandler = AsyncOperationWithProgressCompletedHandler; + + fn set_completed(&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.GetResults() + } + + fn status(&self) -> Result { + self.Status() + } +} diff --git a/crates/libs/future/src/future.rs b/crates/libs/future/src/future.rs index ea814fa6aa..a7b7a5592d 100644 --- a/crates/libs/future/src/future.rs +++ b/crates/libs/future/src/future.rs @@ -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(&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; -} - // 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. @@ -97,7 +71,7 @@ impl Future for AsyncFuture { // 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(); })?; }; @@ -106,94 +80,6 @@ impl Future for AsyncFuture { } } -// -// The four `Async` trait implementations. -// - -impl Async for IAsyncAction { - type Output = (); - type CompletedHandler = AsyncActionCompletedHandler; - - fn set_completed(&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.GetResults() - } -} - -impl Async for IAsyncOperation { - type Output = T; - type CompletedHandler = AsyncOperationCompletedHandler; - - fn set_completed(&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.GetResults() - } -} - -impl Async for IAsyncActionWithProgress

{ - type Output = (); - type CompletedHandler = AsyncActionWithProgressCompletedHandler

; - - fn set_completed(&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.GetResults() - } -} - -impl Async for IAsyncOperationWithProgress { - type Output = T; - type CompletedHandler = AsyncOperationWithProgressCompletedHandler; - - fn set_completed(&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.GetResults() - } -} - // // The four `IntoFuture` trait implementations. // diff --git a/crates/libs/future/src/get.rs b/crates/libs/future/src/get.rs deleted file mode 100644 index 1dfd274db5..0000000000 --- a/crates/libs/future/src/get.rs +++ /dev/null @@ -1,73 +0,0 @@ -use super::*; - -impl IAsyncAction { - /// Waits for the `IAsyncAction` to finish. - pub fn get(&self) -> Result<()> { - if self.Status()? == AsyncStatus::Started { - let (_waiter, signaler) = Waiter::new()?; - self.SetCompleted(&AsyncActionCompletedHandler::new(move |_, _| { - // This is safe because the waiter will only be dropped after being signaled. - unsafe { - signaler.signal(); - } - Ok(()) - }))?; - } - self.GetResults() - } -} - -impl IAsyncOperation { - /// Waits for the `IAsyncOperation` to finish. - pub fn get(&self) -> Result { - if self.Status()? == AsyncStatus::Started { - let (_waiter, signaler) = Waiter::new()?; - self.SetCompleted(&AsyncOperationCompletedHandler::new(move |_, _| { - // This is safe because the waiter will only be dropped after being signaled. - unsafe { - signaler.signal(); - } - Ok(()) - }))?; - } - self.GetResults() - } -} - -impl IAsyncActionWithProgress

{ - /// Waits for the `IAsyncActionWithProgress

` to finish. - pub fn get(&self) -> Result<()> { - if self.Status()? == AsyncStatus::Started { - let (_waiter, signaler) = Waiter::new()?; - self.SetCompleted(&AsyncActionWithProgressCompletedHandler::new( - move |_, _| { - // This is safe because the waiter will only be dropped after being signaled. - unsafe { - signaler.signal(); - } - Ok(()) - }, - ))?; - } - self.GetResults() - } -} - -impl IAsyncOperationWithProgress { - /// Waits for the `IAsyncOperationWithProgress` to finish. - pub fn get(&self) -> Result { - if self.Status()? == AsyncStatus::Started { - let (_waiter, signaler) = Waiter::new()?; - self.SetCompleted(&AsyncOperationWithProgressCompletedHandler::new( - move |_, _| { - // This is safe because the waiter will only be dropped after being signaled. - unsafe { - signaler.signal(); - } - Ok(()) - }, - ))?; - } - self.GetResults() - } -} diff --git a/crates/libs/future/src/join.rs b/crates/libs/future/src/join.rs new file mode 100644 index 0000000000..3e29c62af9 --- /dev/null +++ b/crates/libs/future/src/join.rs @@ -0,0 +1,29 @@ +use super::*; + +impl IAsyncAction { + /// Waits for the `IAsyncAction` to finish. + pub fn join(&self) -> Result<()> { + Async::join(self) + } +} + +impl IAsyncOperation { + /// Waits for the `IAsyncOperation` to finish. + pub fn join(&self) -> Result { + Async::join(self) + } +} + +impl IAsyncActionWithProgress

{ + /// Waits for the `IAsyncActionWithProgress

` to finish. + pub fn join(&self) -> Result<()> { + Async::join(self) + } +} + +impl IAsyncOperationWithProgress { + /// Waits for the `IAsyncOperationWithProgress` to finish. + pub fn join(&self) -> Result { + Async::join(self) + } +} diff --git a/crates/libs/future/src/lib.rs b/crates/libs/future/src/lib.rs index ef74426c10..c5d764ae69 100644 --- a/crates/libs/future/src/lib.rs +++ b/crates/libs/future/src/lib.rs @@ -8,13 +8,16 @@ #![doc = include_str!("../readme.md")] #![cfg_attr(all(not(feature = "std")), no_std)] +mod r#async; mod bindings; mod bindings_impl; -mod get; +mod join; mod waiter; +mod when; pub use bindings::*; use bindings_impl::*; +use r#async::*; use waiter::*; use windows_core::*; @@ -24,5 +27,3 @@ mod async_ready; mod async_spawn; #[cfg(feature = "std")] mod future; -#[cfg(feature = "std")] -use future::*; diff --git a/crates/libs/future/src/when.rs b/crates/libs/future/src/when.rs new file mode 100644 index 0000000000..7f231fac4f --- /dev/null +++ b/crates/libs/future/src/when.rs @@ -0,0 +1,41 @@ +use super::*; + +impl IAsyncAction { + /// Calls `op(result)` when the `IAsyncAction` completes. + pub fn when(&self, op: F) -> Result<()> + where + F: FnOnce(Result<()>) + Send + 'static, + { + Async::when(self, op) + } +} + +impl IAsyncOperation { + /// Calls `op(result)` when the `IAsyncOperation` completes. + pub fn when(&self, op: F) -> Result<()> + where + F: FnOnce(Result) + Send + 'static, + { + Async::when(self, op) + } +} + +impl IAsyncActionWithProgress

{ + /// Calls `op(result)` when the `IAsyncActionWithProgress

` completes. + pub fn when(&self, op: F) -> Result<()> + where + F: FnOnce(Result<()>) + Send + 'static, + { + Async::when(self, op) + } +} + +impl IAsyncOperationWithProgress { + /// Calls `op(result)` when the `IAsyncOperationWithProgress` completes. + pub fn when(&self, op: F) -> Result<()> + where + F: FnOnce(Result) + Send + 'static, + { + Async::when(self, op) + } +} diff --git a/crates/samples/windows/consent/src/main.rs b/crates/samples/windows/consent/src/main.rs index b349d7bc0a..41e47faf3e 100644 --- a/crates/samples/windows/consent/src/main.rs +++ b/crates/samples/windows/consent/src/main.rs @@ -13,7 +13,7 @@ fn main() -> Result<()> { let operation: IAsyncOperation = interop.RequestVerificationForWindowAsync(window, h!("Hello from Rust"))?; - let result: UserConsentVerificationResult = operation.get()?; + let result: UserConsentVerificationResult = operation.join()?; println!("{result:?}"); diff --git a/crates/samples/windows/data_protection/src/main.rs b/crates/samples/windows/data_protection/src/main.rs index 8b434a86a0..79b4c9bba7 100644 --- a/crates/samples/windows/data_protection/src/main.rs +++ b/crates/samples/windows/data_protection/src/main.rs @@ -8,13 +8,13 @@ fn main() -> std::io::Result<()> { let unprotected = CryptographicBuffer::ConvertStringToBinary(h!("Hello world"), BinaryStringEncoding::Utf8)?; - let protected = provider.ProtectAsync(&unprotected)?.get()?; + let protected = provider.ProtectAsync(&unprotected)?.join()?; let protected_bytes = unsafe { as_mut_bytes(&protected)? }; std::fs::write("secret.bin", protected_bytes)?; let protected_bytes = std::fs::read("secret.bin")?; let protected = CryptographicBuffer::CreateFromByteArray(&protected_bytes)?; - let unprotected = provider.UnprotectAsync(&protected)?.get()?; + let unprotected = provider.UnprotectAsync(&protected)?.join()?; let message = CryptographicBuffer::ConvertBinaryToString(BinaryStringEncoding::Utf8, &unprotected)?; diff --git a/crates/samples/windows/ocr/src/main.rs b/crates/samples/windows/ocr/src/main.rs index 4dc85d8d06..37974ae937 100644 --- a/crates/samples/windows/ocr/src/main.rs +++ b/crates/samples/windows/ocr/src/main.rs @@ -10,14 +10,14 @@ fn main() -> Result<()> { message.push("message.png"); let file = - StorageFile::GetFileFromPathAsync(&HSTRING::from(message.to_str().unwrap()))?.get()?; - let stream = file.OpenAsync(FileAccessMode::Read)?.get()?; + StorageFile::GetFileFromPathAsync(&HSTRING::from(message.to_str().unwrap()))?.join()?; + let stream = file.OpenAsync(FileAccessMode::Read)?.join()?; - let decode = BitmapDecoder::CreateAsync(&stream)?.get()?; - let bitmap = decode.GetSoftwareBitmapAsync()?.get()?; + let decode = BitmapDecoder::CreateAsync(&stream)?.join()?; + let bitmap = decode.GetSoftwareBitmapAsync()?.join()?; let engine = OcrEngine::TryCreateFromUserProfileLanguages()?; - let result = engine.RecognizeAsync(&bitmap)?.get()?; + let result = engine.RecognizeAsync(&bitmap)?.join()?; println!("{}", result.Text()?); Ok(()) diff --git a/crates/samples/windows/rss/src/main.rs b/crates/samples/windows/rss/src/main.rs index fe7b9e8239..8e5df10f9e 100644 --- a/crates/samples/windows/rss/src/main.rs +++ b/crates/samples/windows/rss/src/main.rs @@ -9,7 +9,7 @@ fn main() -> Result<()> { h!("Mozilla/5.0 (compatible; MSIE 10.0; Windows NT 6.2; WOW64; Trident/6.0)"), )?; - let feed = client.RetrieveFeedAsync(&uri)?.get()?; + let feed = client.RetrieveFeedAsync(&uri)?.join()?; for item in feed.Items()? { println!("{}", item.Title()?.Text()?); diff --git a/crates/tests/libs/future/Cargo.toml b/crates/tests/libs/future/Cargo.toml index 96e51ce112..acb7e00b91 100644 --- a/crates/tests/libs/future/Cargo.toml +++ b/crates/tests/libs/future/Cargo.toml @@ -20,5 +20,11 @@ features = [ workspace = true features = ["std"] +[dev-dependencies.windows-result] +workspace = true + +[dev-dependencies.windows-threading] +workspace = true + [dev-dependencies] futures = "0.3" diff --git a/crates/tests/libs/future/tests/async_info.rs b/crates/tests/libs/future/tests/async_info.rs index 6c176235de..626f457825 100644 --- a/crates/tests/libs/future/tests/async_info.rs +++ b/crates/tests/libs/future/tests/async_info.rs @@ -7,35 +7,35 @@ use windows_future::*; #[test] fn test() -> Result<()> { let a = IAsyncAction::ready(Ok(())); - a.get()?; + a.join()?; async_info(&a.cast()?)?; let a = IAsyncActionWithProgress::::ready(Ok(())); - a.get()?; + a.join()?; async_info(&a.cast()?)?; let a = IAsyncOperation::::ready(Ok(123)); - assert_eq!(a.get()?, 123); + assert_eq!(a.join()?, 123); async_info(&a.cast()?)?; let a = IAsyncOperationWithProgress::::ready(Ok(123)); - assert_eq!(a.get()?, 123); + assert_eq!(a.join()?, 123); async_info(&a.cast()?)?; let a = IAsyncAction::spawn(|| Ok(())); - a.get()?; + a.join()?; async_info(&a.cast()?)?; let a = IAsyncOperation::spawn(|| Ok(123)); - assert_eq!(a.get()?, 123); + assert_eq!(a.join()?, 123); async_info(&a.cast()?)?; let a = IAsyncActionWithProgress::::spawn(|| Ok(())); - a.get()?; + a.join()?; async_info(&a.cast()?)?; let a = IAsyncOperationWithProgress::::spawn(|| Ok(123)); - assert_eq!(a.get()?, 123); + assert_eq!(a.join()?, 123); async_info(&a.cast()?)?; Ok(()) diff --git a/crates/tests/libs/future/tests/completed_get.rs b/crates/tests/libs/future/tests/completed_get.rs index a68957caa6..994adc0e1d 100644 --- a/crates/tests/libs/future/tests/completed_get.rs +++ b/crates/tests/libs/future/tests/completed_get.rs @@ -7,35 +7,35 @@ use windows_future::*; #[test] fn test() -> Result<()> { let a = IAsyncAction::ready(Ok(())); - a.get()?; + a.join()?; assert_eq!(a.Completed(), Err(Error::empty())); let a = IAsyncActionWithProgress::::ready(Ok(())); - a.get()?; + a.join()?; assert_eq!(a.Completed(), Err(Error::empty())); let a = IAsyncOperation::::ready(Ok(1)); - a.get()?; + a.join()?; assert_eq!(a.Completed(), Err(Error::empty())); let a = IAsyncOperationWithProgress::::ready(Ok(1)); - a.get()?; + a.join()?; assert_eq!(a.Completed(), Err(Error::empty())); let a = IAsyncAction::spawn(|| Ok(())); - a.get()?; + a.join()?; assert_eq!(a.Completed(), Err(Error::empty())); let a = IAsyncOperation::spawn(|| Ok(123)); - a.get()?; + a.join()?; assert_eq!(a.Completed(), Err(Error::empty())); let a = IAsyncActionWithProgress::::spawn(|| Ok(())); - a.get()?; + a.join()?; assert_eq!(a.Completed(), Err(Error::empty())); let a = IAsyncOperationWithProgress::::spawn(|| Ok(123)); - a.get()?; + a.join()?; assert_eq!(a.Completed(), Err(Error::empty())); Ok(()) diff --git a/crates/tests/libs/future/tests/error.rs b/crates/tests/libs/future/tests/error.rs index 222d6ca3d1..b37437a611 100644 --- a/crates/tests/libs/future/tests/error.rs +++ b/crates/tests/libs/future/tests/error.rs @@ -11,7 +11,7 @@ fn action_ready() -> Result<()> { E_PROTOCOL_EXTENSIONS_NOT_SUPPORTED, "async", ))); - let e = a.get().unwrap_err(); + let e = a.join().unwrap_err(); assert_eq!(e.message(), "async"); assert_eq!(e.code(), E_PROTOCOL_EXTENSIONS_NOT_SUPPORTED); assert_eq!(a.ErrorCode()?, E_PROTOCOL_EXTENSIONS_NOT_SUPPORTED); @@ -26,7 +26,7 @@ fn action_with_progress_ready() -> Result<()> { E_PROTOCOL_EXTENSIONS_NOT_SUPPORTED, "async", ))); - let e = a.get().unwrap_err(); + let e = a.join().unwrap_err(); assert_eq!(e.message(), "async"); assert_eq!(e.code(), E_PROTOCOL_EXTENSIONS_NOT_SUPPORTED); assert_eq!(a.ErrorCode()?, E_PROTOCOL_EXTENSIONS_NOT_SUPPORTED); @@ -41,7 +41,7 @@ fn operation_ready() -> Result<()> { E_PROTOCOL_EXTENSIONS_NOT_SUPPORTED, "async", ))); - let e = a.get().unwrap_err(); + let e = a.join().unwrap_err(); assert_eq!(e.message(), "async"); assert_eq!(e.code(), E_PROTOCOL_EXTENSIONS_NOT_SUPPORTED); assert_eq!(a.ErrorCode()?, E_PROTOCOL_EXTENSIONS_NOT_SUPPORTED); @@ -56,7 +56,7 @@ fn operation_with_progress_ready() -> Result<()> { E_PROTOCOL_EXTENSIONS_NOT_SUPPORTED, "async", ))); - let e = a.get().unwrap_err(); + let e = a.join().unwrap_err(); assert_eq!(e.message(), "async"); assert_eq!(e.code(), E_PROTOCOL_EXTENSIONS_NOT_SUPPORTED); assert_eq!(a.ErrorCode()?, E_PROTOCOL_EXTENSIONS_NOT_SUPPORTED); @@ -69,7 +69,7 @@ fn operation_with_progress_ready() -> Result<()> { fn action_spawn() -> Result<()> { let error_clone = Error::new(E_PROTOCOL_EXTENSIONS_NOT_SUPPORTED, "async"); let a = IAsyncAction::spawn(move || Err(error_clone)); - let e = a.get().unwrap_err(); + let e = a.join().unwrap_err(); assert_eq!(e.message(), "async"); assert_eq!(e.code(), E_PROTOCOL_EXTENSIONS_NOT_SUPPORTED); assert_eq!(a.ErrorCode()?, E_PROTOCOL_EXTENSIONS_NOT_SUPPORTED); @@ -82,7 +82,7 @@ fn action_spawn() -> Result<()> { fn operation_spawn() -> Result<()> { let error_clone = Error::new(E_PROTOCOL_EXTENSIONS_NOT_SUPPORTED, "async"); let a = IAsyncOperation::::spawn(move || Err(error_clone)); - let e = a.get().unwrap_err(); + let e = a.join().unwrap_err(); assert_eq!(e.message(), "async"); assert_eq!(e.code(), E_PROTOCOL_EXTENSIONS_NOT_SUPPORTED); assert_eq!(a.ErrorCode()?, E_PROTOCOL_EXTENSIONS_NOT_SUPPORTED); @@ -95,7 +95,7 @@ fn operation_spawn() -> Result<()> { fn action_with_progress_spawn() -> Result<()> { let error_clone = Error::new(E_PROTOCOL_EXTENSIONS_NOT_SUPPORTED, "async"); let a = IAsyncActionWithProgress::::spawn(move || Err(error_clone)); - let e = a.get().unwrap_err(); + let e = a.join().unwrap_err(); assert_eq!(e.message(), "async"); assert_eq!(e.code(), E_PROTOCOL_EXTENSIONS_NOT_SUPPORTED); assert_eq!(a.ErrorCode()?, E_PROTOCOL_EXTENSIONS_NOT_SUPPORTED); @@ -108,7 +108,7 @@ fn action_with_progress_spawn() -> Result<()> { fn operation_with_progress_spawn() -> Result<()> { let error_clone = Error::new(E_PROTOCOL_EXTENSIONS_NOT_SUPPORTED, "async"); let a = IAsyncOperationWithProgress::::spawn(move || Err(error_clone)); - let e = a.get().unwrap_err(); + let e = a.join().unwrap_err(); assert_eq!(e.message(), "async"); assert_eq!(e.code(), E_PROTOCOL_EXTENSIONS_NOT_SUPPORTED); assert_eq!(a.ErrorCode()?, E_PROTOCOL_EXTENSIONS_NOT_SUPPORTED); diff --git a/crates/tests/libs/future/tests/futures.rs b/crates/tests/libs/future/tests/futures.rs index d849a365ea..123e7f8f4c 100644 --- a/crates/tests/libs/future/tests/futures.rs +++ b/crates/tests/libs/future/tests/futures.rs @@ -6,7 +6,7 @@ use windows::{core::*, Storage::Streams::*, System::Threading::*}; // A simple example of blocking synchronously with the `get` method. #[test] fn simple_sync() -> Result<()> { - ThreadPool::RunAsync(&WorkItemHandler::new(|_| Ok(())))?.get() + ThreadPool::RunAsync(&WorkItemHandler::new(|_| Ok(())))?.join() } // A simple example of awaiting with an async function. diff --git a/crates/tests/libs/future/tests/progress.rs b/crates/tests/libs/future/tests/progress.rs index c5bbe3b0e9..72e8012a8a 100644 --- a/crates/tests/libs/future/tests/progress.rs +++ b/crates/tests/libs/future/tests/progress.rs @@ -6,22 +6,22 @@ use windows_future::*; #[test] fn test() -> Result<()> { let a = IAsyncActionWithProgress::::ready(Ok(())); - a.get()?; + a.join()?; a.SetProgress(&AsyncActionProgressHandler::new(|_, _| Ok(())))?; assert_eq!(a.Progress(), Err(Error::empty())); let a = IAsyncOperationWithProgress::::ready(Ok(1)); - a.get()?; + a.join()?; a.SetProgress(&AsyncOperationProgressHandler::new(|_, _| Ok(())))?; assert_eq!(a.Progress(), Err(Error::empty())); let a = IAsyncActionWithProgress::::spawn(|| Ok(())); - a.get()?; + a.join()?; a.SetProgress(&AsyncActionProgressHandler::new(|_, _| Ok(())))?; assert_eq!(a.Progress(), Err(Error::empty())); let a = IAsyncOperationWithProgress::::spawn(|| Ok(123)); - a.get()?; + a.join()?; a.SetProgress(&AsyncOperationProgressHandler::new(|_, _| Ok(())))?; assert_eq!(a.Progress(), Err(Error::empty())); diff --git a/crates/tests/libs/future/tests/started.rs b/crates/tests/libs/future/tests/started.rs index 978991dc9e..5d7a03d7e1 100644 --- a/crates/tests/libs/future/tests/started.rs +++ b/crates/tests/libs/future/tests/started.rs @@ -17,7 +17,7 @@ fn action() -> Result<()> { assert_eq!(a.Status()?, AsyncStatus::Started); assert_eq!(a.GetResults().unwrap_err().code(), E_ILLEGAL_METHOD_CALL); send.send(()).unwrap(); - a.get()?; + a.join()?; Ok(()) } @@ -34,7 +34,7 @@ fn operation() -> Result<()> { assert_eq!(a.Status()?, AsyncStatus::Started); assert_eq!(a.GetResults().unwrap_err().code(), E_ILLEGAL_METHOD_CALL); send.send(()).unwrap(); - assert_eq!(a.get()?, 123); + assert_eq!(a.join()?, 123); Ok(()) } @@ -51,7 +51,7 @@ fn action_with_progress() -> Result<()> { assert_eq!(a.Status()?, AsyncStatus::Started); assert_eq!(a.GetResults().unwrap_err().code(), E_ILLEGAL_METHOD_CALL); send.send(()).unwrap(); - a.get()?; + a.join()?; Ok(()) } @@ -68,7 +68,7 @@ fn operation_with_progress() -> Result<()> { assert_eq!(a.Status()?, AsyncStatus::Started); assert_eq!(a.GetResults().unwrap_err().code(), E_ILLEGAL_METHOD_CALL); send.send(()).unwrap(); - assert_eq!(a.get()?, 123); + assert_eq!(a.join()?, 123); Ok(()) } diff --git a/crates/tests/libs/future/tests/when.rs b/crates/tests/libs/future/tests/when.rs new file mode 100644 index 0000000000..c9367a4737 --- /dev/null +++ b/crates/tests/libs/future/tests/when.rs @@ -0,0 +1,135 @@ +use windows::Win32::Foundation::E_FAIL; +use windows_future::*; +use windows_result::*; + +#[test] +fn ok() -> Result<()> { + let a = IAsyncAction::ready(Ok(())); + + a.when(move |r| { + assert!(r.is_ok()); + })?; + + let a = IAsyncAction::spawn(|| Ok(())); + + a.when(move |r| { + assert!(r.is_ok()); + })?; + + let a = IAsyncActionWithProgress::::ready(Ok(())); + + a.when(move |r| { + assert!(r.is_ok()); + })?; + + let a = IAsyncActionWithProgress::::spawn(|| Ok(())); + + a.when(move |r| { + assert!(r.is_ok()); + })?; + + let a = IAsyncOperation::::ready(Ok(123)); + + a.when(move |r| { + assert_eq!(r, Ok(123)); + })?; + + let a = IAsyncOperation::::spawn(|| Ok(456)); + + a.when(move |r| { + assert_eq!(r, Ok(456)); + })?; + + let a = IAsyncOperationWithProgress::::ready(Ok(123)); + + a.when(move |r| { + assert_eq!(r, Ok(123)); + })?; + + let a = IAsyncOperationWithProgress::::spawn(|| Ok(456)); + + a.when(move |r| { + assert_eq!(r, Ok(456)); + })?; + + Ok(()) +} + +#[test] +fn err() -> Result<()> { + let a = IAsyncAction::ready(Err(Error::new(E_FAIL, "IAsyncAction-ready"))); + + a.when(move |r| { + let err = r.unwrap_err(); + assert_eq!(err.code(), E_FAIL); + assert_eq!(err.message(), "IAsyncAction-ready"); + })?; + + let a = IAsyncAction::spawn(|| Err(Error::new(E_FAIL, "IAsyncAction-spawn"))); + + a.when(move |r| { + let err = r.unwrap_err(); + assert_eq!(err.code(), E_FAIL); + assert_eq!(err.message(), "IAsyncAction-spawn"); + })?; + + let a = IAsyncActionWithProgress::::ready(Err(Error::new( + E_FAIL, + "IAsyncActionWithProgress-ready", + ))); + + a.when(move |r| { + let err = r.unwrap_err(); + assert_eq!(err.code(), E_FAIL); + assert_eq!(err.message(), "IAsyncActionWithProgress-ready"); + })?; + + let a = IAsyncActionWithProgress::::spawn(|| { + Err(Error::new(E_FAIL, "IAsyncActionWithProgress-spawn")) + }); + + a.when(move |r| { + let err = r.unwrap_err(); + assert_eq!(err.code(), E_FAIL); + assert_eq!(err.message(), "IAsyncActionWithProgress-spawn"); + })?; + + let a = IAsyncOperation::::ready(Err(Error::new(E_FAIL, "IAsyncOperation-ready"))); + + a.when(move |r| { + let err = r.unwrap_err(); + assert_eq!(err.code(), E_FAIL); + assert_eq!(err.message(), "IAsyncOperation-ready"); + })?; + + let a = IAsyncOperation::::spawn(|| Err(Error::new(E_FAIL, "IAsyncOperation-spawn"))); + + a.when(move |r| { + let err = r.unwrap_err(); + assert_eq!(err.code(), E_FAIL); + assert_eq!(err.message(), "IAsyncOperation-spawn"); + })?; + + let a = IAsyncOperationWithProgress::::ready(Err(Error::new( + E_FAIL, + "IAsyncOperationWithProgress-ready", + ))); + + a.when(move |r| { + let err = r.unwrap_err(); + assert_eq!(err.code(), E_FAIL); + assert_eq!(err.message(), "IAsyncOperationWithProgress-ready"); + })?; + + let a = IAsyncOperationWithProgress::::spawn(|| { + Err(Error::new(E_FAIL, "IAsyncOperationWithProgress-spawn")) + }); + + a.when(move |r| { + let err = r.unwrap_err(); + assert_eq!(err.code(), E_FAIL); + assert_eq!(err.message(), "IAsyncOperationWithProgress-spawn"); + })?; + + Ok(()) +} diff --git a/crates/tests/misc/agile_reference/tests/tests.rs b/crates/tests/misc/agile_reference/tests/tests.rs index 249fc397fe..b9703bdc85 100644 --- a/crates/tests/misc/agile_reference/tests/tests.rs +++ b/crates/tests/misc/agile_reference/tests/tests.rs @@ -2,7 +2,7 @@ use windows::{core::*, Foundation::*, Media::Control::*}; #[test] fn agile_send() -> Result<()> { - let manager = GlobalSystemMediaTransportControlsSessionManager::RequestAsync()?.get()?; + let manager = GlobalSystemMediaTransportControlsSessionManager::RequestAsync()?.join()?; let reference = AgileReference::new(&manager)?; let handle = std::thread::spawn(move || { diff --git a/crates/tests/winrt/old/tests/async.rs b/crates/tests/winrt/old/tests/async.rs index 8ce9a224ae..5fc0bec237 100644 --- a/crates/tests/winrt/old/tests/async.rs +++ b/crates/tests/winrt/old/tests/async.rs @@ -8,11 +8,11 @@ fn async_get() -> windows::core::Result<()> { writer.WriteByte(1)?; writer.WriteByte(2)?; writer.WriteByte(3)?; - writer.StoreAsync()?.get()?; + writer.StoreAsync()?.join()?; stream.Seek(0)?; let reader = DataReader::CreateDataReader(stream)?; - reader.LoadAsync(3)?.get()?; + reader.LoadAsync(3)?.join()?; let mut bytes: [u8; 3] = [0; 3]; reader.ReadBytes(&mut bytes)?; diff --git a/crates/tests/winrt/old/tests/collisions.rs b/crates/tests/winrt/old/tests/collisions.rs index 9c7c64e5d2..91c8a576bc 100644 --- a/crates/tests/winrt/old/tests/collisions.rs +++ b/crates/tests/winrt/old/tests/collisions.rs @@ -16,7 +16,7 @@ fn wifi() -> windows::core::Result<()> { assert!(!a.is_empty()); // from_id_async from IWiFiDirectDeviceStatics - assert!(WiFiDirectDevice::FromIdAsync(&a)?.get() == Err(windows::core::Error::empty())); + assert!(WiFiDirectDevice::FromIdAsync(&a)?.join() == Err(windows::core::Error::empty())); // get_device_selector overload from IWiFiDirectDeviceStatics2 is renamed to get_device_selector2 let c = WiFiDirectDevice::GetDeviceSelector2(WiFiDirectDeviceSelectorType::DeviceInterface)?; diff --git a/crates/tests/winrt/old/tests/send_sync.rs b/crates/tests/winrt/old/tests/send_sync.rs index 06a62f64cd..2f361966e8 100644 --- a/crates/tests/winrt/old/tests/send_sync.rs +++ b/crates/tests/winrt/old/tests/send_sync.rs @@ -28,14 +28,14 @@ fn send_async() { let store_async = writer.StoreAsync().unwrap(); let wait = thread::spawn(move || { - store_async.get().unwrap(); + store_async.join().unwrap(); stream.Seek(0).unwrap(); let reader = DataReader::CreateDataReader(&stream).unwrap(); let load_async = reader.LoadAsync(3).unwrap(); let wait = thread::spawn(move || { - load_async.get().unwrap(); + load_async.join().unwrap(); let mut bytes: [u8; 3] = [0; 3]; reader.ReadBytes(&mut bytes).unwrap(); @@ -62,14 +62,14 @@ fn send_async_no_class() { let store_async: IAsyncOperation = writer.StoreAsync().unwrap().cast().unwrap(); let wait = thread::spawn(move || { - store_async.get().unwrap(); + store_async.join().unwrap(); stream.Seek(0).unwrap(); let reader = DataReader::CreateDataReader(&stream).unwrap(); let load_async: IAsyncOperation = reader.LoadAsync(3).unwrap().cast().unwrap(); let wait = thread::spawn(move || { - load_async.get().unwrap(); + load_async.join().unwrap(); let mut bytes: [u8; 3] = [0; 3]; reader.ReadBytes(&mut bytes).unwrap();