Skip to content

Commit

Permalink
Implement IntoFuture for winrt futures
Browse files Browse the repository at this point in the history
  • Loading branch information
goffrie committed Jul 24, 2024
1 parent 02c4f29 commit 89c3928
Show file tree
Hide file tree
Showing 11 changed files with 458 additions and 5 deletions.
25 changes: 25 additions & 0 deletions crates/libs/bindgen/src/rust/writer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -697,6 +697,31 @@ impl Writer {
self.GetResults()
}
}
#features
impl<#constraints> windows_core::AsyncOperation for #ident {
type Output = #return_type;
fn is_complete(&self) -> windows_core::Result<bool> {
Ok(self.Status()? != #namespace AsyncStatus::Started)
}
fn set_completed(&self, f: impl Fn() + Send + 'static) -> windows_core::Result<()> {
self.SetCompleted(&#namespace #handler::new(move |_sender, _args| {
f();
Ok(())
}))
}
fn get_results(&self) -> windows_core::Result<Self::Output> {
self.GetResults()
}
}
#features
impl<#constraints> std::future::IntoFuture for #ident {
type Output = windows_core::Result<#return_type>;
type IntoFuture = windows_core::FutureWrapper<#ident>;

fn into_future(self) -> Self::IntoFuture {
windows_core::FutureWrapper::new(self)
}
}
}
}
}
Expand Down
68 changes: 68 additions & 0 deletions crates/libs/core/src/future.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
#![cfg(feature = "std")]

use std::{
future::Future,
pin::Pin,
sync::{Arc, Mutex},
task::{Poll, Waker},
};

/// Wraps an `IAsyncOperation`, `IAsyncOperationWithProgress`, `IAsyncAction`, or `IAsyncActionWithProgress`.
/// Impls for this trait are generated automatically by windows-bindgen.
pub trait AsyncOperation {
/// The type produced when the operation finishes.
type Output;
/// Returns whether the operation is finished, in which case `self.get_results()` can be used to get the returned data.
/// Wraps `self.Status() != AsyncStatus::Started`.
fn is_complete(&self) -> crate::Result<bool>;
/// Register a callback that will be called once the operation is finished.
/// This can only be called once.
/// Wraps `self.SetCompleted(f)`.
fn set_completed(&self, f: impl Fn() + Send + 'static) -> crate::Result<()>;
/// Get the result value from a completed operation.
/// Wraps `self.GetResults()`.
fn get_results(&self) -> crate::Result<Self::Output>;
}

/// A wrapper around an `AsyncOperation` that implements `std::future::Future`.
/// This is used by generated `IntoFuture` impls. It shouldn't be necessary to use this type manually.
pub struct FutureWrapper<T> {
inner: T,
waker: Option<Arc<Mutex<Waker>>>,
}

impl<T> FutureWrapper<T> {
/// Creates a `FutureWrapper`, which implements `std::future::Future`.
pub fn new(inner: T) -> Self {
Self {
inner,
waker: None,
}
}
}

impl<T> Unpin for FutureWrapper<T> {}

impl<T: AsyncOperation> Future for FutureWrapper<T> {
type Output = crate::Result<T::Output>;

fn poll(mut self: Pin<&mut Self>, cx: &mut std::task::Context<'_>) -> Poll<Self::Output> {
if self.inner.is_complete()? {
Poll::Ready(self.inner.get_results())
} else {
if let Some(saved_waker) = &self.waker {
// Update the saved waker, in case the future has been transferred to a different executor.
// (e.g. if using `select`.)
let mut saved_waker = saved_waker.lock().unwrap();
saved_waker.clone_from(cx.waker());
} else {
let saved_waker = Arc::new(Mutex::new(cx.waker().clone()));
self.waker = Some(saved_waker.clone());
self.inner.set_completed(move || {
saved_waker.lock().unwrap().wake_by_ref();
})?;
}
Poll::Pending
}
}
}
2 changes: 2 additions & 0 deletions crates/libs/core/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ pub mod imp;

mod as_impl;
mod com_object;
mod future;
mod guid;
mod inspectable;
mod interface;
Expand All @@ -41,6 +42,7 @@ mod weak;

pub use as_impl::*;
pub use com_object::*;
pub use future::*;
pub use guid::*;
pub use inspectable::*;
pub use interface::*;
Expand Down
144 changes: 144 additions & 0 deletions crates/libs/windows/src/Windows/Devices/Sms/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1036,6 +1036,30 @@ impl DeleteSmsMessageOperation {
}
}
#[cfg(feature = "deprecated")]
impl windows_core::AsyncOperation for DeleteSmsMessageOperation {
type Output = ();
fn is_complete(&self) -> windows_core::Result<bool> {
Ok(self.Status()? != super::super::Foundation::AsyncStatus::Started)
}
fn set_completed(&self, f: impl Fn() + Send + 'static) -> windows_core::Result<()> {
self.SetCompleted(&super::super::Foundation::AsyncActionCompletedHandler::new(move |_sender, _args| {
f();
Ok(())
}))
}
fn get_results(&self) -> windows_core::Result<Self::Output> {
self.GetResults()
}
}
#[cfg(feature = "deprecated")]
impl std::future::IntoFuture for DeleteSmsMessageOperation {
type Output = windows_core::Result<()>;
type IntoFuture = windows_core::FutureWrapper<DeleteSmsMessageOperation>;
fn into_future(self) -> Self::IntoFuture {
windows_core::FutureWrapper::new(self)
}
}
#[cfg(feature = "deprecated")]
#[repr(transparent)]
#[derive(PartialEq, Eq, Debug, Clone)]
pub struct DeleteSmsMessagesOperation(windows_core::IUnknown);
Expand Down Expand Up @@ -1122,6 +1146,30 @@ impl DeleteSmsMessagesOperation {
}
}
#[cfg(feature = "deprecated")]
impl windows_core::AsyncOperation for DeleteSmsMessagesOperation {
type Output = ();
fn is_complete(&self) -> windows_core::Result<bool> {
Ok(self.Status()? != super::super::Foundation::AsyncStatus::Started)
}
fn set_completed(&self, f: impl Fn() + Send + 'static) -> windows_core::Result<()> {
self.SetCompleted(&super::super::Foundation::AsyncActionCompletedHandler::new(move |_sender, _args| {
f();
Ok(())
}))
}
fn get_results(&self) -> windows_core::Result<Self::Output> {
self.GetResults()
}
}
#[cfg(feature = "deprecated")]
impl std::future::IntoFuture for DeleteSmsMessagesOperation {
type Output = windows_core::Result<()>;
type IntoFuture = windows_core::FutureWrapper<DeleteSmsMessagesOperation>;
fn into_future(self) -> Self::IntoFuture {
windows_core::FutureWrapper::new(self)
}
}
#[cfg(feature = "deprecated")]
#[repr(transparent)]
#[derive(PartialEq, Eq, Debug, Clone)]
pub struct GetSmsDeviceOperation(windows_core::IUnknown);
Expand Down Expand Up @@ -1211,6 +1259,30 @@ impl GetSmsDeviceOperation {
}
}
#[cfg(feature = "deprecated")]
impl windows_core::AsyncOperation for GetSmsDeviceOperation {
type Output = SmsDevice;
fn is_complete(&self) -> windows_core::Result<bool> {
Ok(self.Status()? != super::super::Foundation::AsyncStatus::Started)
}
fn set_completed(&self, f: impl Fn() + Send + 'static) -> windows_core::Result<()> {
self.SetCompleted(&super::super::Foundation::AsyncOperationCompletedHandler::new(move |_sender, _args| {
f();
Ok(())
}))
}
fn get_results(&self) -> windows_core::Result<Self::Output> {
self.GetResults()
}
}
#[cfg(feature = "deprecated")]
impl std::future::IntoFuture for GetSmsDeviceOperation {
type Output = windows_core::Result<SmsDevice>;
type IntoFuture = windows_core::FutureWrapper<GetSmsDeviceOperation>;
fn into_future(self) -> Self::IntoFuture {
windows_core::FutureWrapper::new(self)
}
}
#[cfg(feature = "deprecated")]
#[repr(transparent)]
#[derive(PartialEq, Eq, Debug, Clone)]
pub struct GetSmsMessageOperation(windows_core::IUnknown);
Expand Down Expand Up @@ -1299,6 +1371,30 @@ impl GetSmsMessageOperation {
self.GetResults()
}
}
#[cfg(feature = "deprecated")]
impl windows_core::AsyncOperation for GetSmsMessageOperation {
type Output = ISmsMessage;
fn is_complete(&self) -> windows_core::Result<bool> {
Ok(self.Status()? != super::super::Foundation::AsyncStatus::Started)
}
fn set_completed(&self, f: impl Fn() + Send + 'static) -> windows_core::Result<()> {
self.SetCompleted(&super::super::Foundation::AsyncOperationCompletedHandler::new(move |_sender, _args| {
f();
Ok(())
}))
}
fn get_results(&self) -> windows_core::Result<Self::Output> {
self.GetResults()
}
}
#[cfg(feature = "deprecated")]
impl std::future::IntoFuture for GetSmsMessageOperation {
type Output = windows_core::Result<ISmsMessage>;
type IntoFuture = windows_core::FutureWrapper<GetSmsMessageOperation>;
fn into_future(self) -> Self::IntoFuture {
windows_core::FutureWrapper::new(self)
}
}
#[cfg(all(feature = "Foundation_Collections", feature = "deprecated"))]
#[repr(transparent)]
#[derive(PartialEq, Eq, Debug, Clone)]
Expand Down Expand Up @@ -1407,6 +1503,30 @@ impl GetSmsMessagesOperation {
self.GetResults()
}
}
#[cfg(all(feature = "Foundation_Collections", feature = "deprecated"))]
impl windows_core::AsyncOperation for GetSmsMessagesOperation {
type Output = super::super::Foundation::Collections::IVectorView<ISmsMessage>;
fn is_complete(&self) -> windows_core::Result<bool> {
Ok(self.Status()? != super::super::Foundation::AsyncStatus::Started)
}
fn set_completed(&self, f: impl Fn() + Send + 'static) -> windows_core::Result<()> {
self.SetCompleted(&super::super::Foundation::AsyncOperationWithProgressCompletedHandler::new(move |_sender, _args| {
f();
Ok(())
}))
}
fn get_results(&self) -> windows_core::Result<Self::Output> {
self.GetResults()
}
}
#[cfg(all(feature = "Foundation_Collections", feature = "deprecated"))]
impl std::future::IntoFuture for GetSmsMessagesOperation {
type Output = windows_core::Result<super::super::Foundation::Collections::IVectorView<ISmsMessage>>;
type IntoFuture = windows_core::FutureWrapper<GetSmsMessagesOperation>;
fn into_future(self) -> Self::IntoFuture {
windows_core::FutureWrapper::new(self)
}
}
#[cfg(feature = "deprecated")]
#[repr(transparent)]
#[derive(PartialEq, Eq, Debug, Clone)]
Expand Down Expand Up @@ -1493,6 +1613,30 @@ impl SendSmsMessageOperation {
self.GetResults()
}
}
#[cfg(feature = "deprecated")]
impl windows_core::AsyncOperation for SendSmsMessageOperation {
type Output = ();
fn is_complete(&self) -> windows_core::Result<bool> {
Ok(self.Status()? != super::super::Foundation::AsyncStatus::Started)
}
fn set_completed(&self, f: impl Fn() + Send + 'static) -> windows_core::Result<()> {
self.SetCompleted(&super::super::Foundation::AsyncActionCompletedHandler::new(move |_sender, _args| {
f();
Ok(())
}))
}
fn get_results(&self) -> windows_core::Result<Self::Output> {
self.GetResults()
}
}
#[cfg(feature = "deprecated")]
impl std::future::IntoFuture for SendSmsMessageOperation {
type Output = windows_core::Result<()>;
type IntoFuture = windows_core::FutureWrapper<SendSmsMessageOperation>;
fn into_future(self) -> Self::IntoFuture {
windows_core::FutureWrapper::new(self)
}
}
#[repr(transparent)]
#[derive(PartialEq, Eq, Debug, Clone)]
pub struct SmsAppMessage(windows_core::IUnknown);
Expand Down
Loading

0 comments on commit 89c3928

Please sign in to comment.