Skip to content

Commit

Permalink
Overhaul async and future support (#3213)
Browse files Browse the repository at this point in the history
  • Loading branch information
kennykerr authored Aug 22, 2024
1 parent 5535b36 commit 0fb1a7f
Show file tree
Hide file tree
Showing 15 changed files with 429 additions and 1,028 deletions.
2 changes: 2 additions & 0 deletions .github/workflows/clippy.yml
Original file line number Diff line number Diff line change
Expand Up @@ -171,6 +171,8 @@ jobs:
run: cargo clippy -p test_event
- name: Clippy test_extensions
run: cargo clippy -p test_extensions
- name: Clippy test_futures
run: cargo clippy -p test_futures
- name: Clippy test_handles
run: cargo clippy -p test_handles
- name: Clippy test_helpers
Expand Down
2 changes: 2 additions & 0 deletions .github/workflows/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -197,6 +197,8 @@ jobs:
run: cargo test -p test_event --target ${{ matrix.target }} ${{ matrix.etc }}
- name: Test test_extensions
run: cargo test -p test_extensions --target ${{ matrix.target }} ${{ matrix.etc }}
- name: Test test_futures
run: cargo test -p test_futures --target ${{ matrix.target }} ${{ matrix.etc }}
- name: Test test_handles
run: cargo test -p test_handles --target ${{ matrix.target }} ${{ matrix.etc }}
- name: Test test_helpers
Expand Down
9 changes: 0 additions & 9 deletions crates/libs/bindgen/src/metadata.rs
Original file line number Diff line number Diff line change
Expand Up @@ -60,15 +60,6 @@ pub struct SignatureParam {
pub kind: SignatureParamKind,
}

#[derive(PartialEq, Eq, Debug)]
pub enum AsyncKind {
None,
Action,
ActionWithProgress,
Operation,
OperationWithProgress,
}

#[derive(Clone, PartialEq, Eq, Default)]
pub struct Guid(
pub u32,
Expand Down
45 changes: 34 additions & 11 deletions crates/libs/bindgen/src/rust/classes.rs
Original file line number Diff line number Diff line change
Expand Up @@ -29,13 +29,25 @@ fn gen_class(writer: &Writer, def: metadata::TypeDef) -> TokenStream {
}

let name = to_ident(def.name());
let cfg = cfg::type_def_cfg(writer, def, &[]);
let features = writer.cfg_features(&cfg);
let interfaces = metadata::type_interfaces(&metadata::Type::TypeDef(def, Vec::new()));

// If the default interface is one of the async interfaces then we can simply replace it with a type alias
// for the async interface. This simplifies and reduces code gen and but also provides a more streamlined
// developer experience. This works because the default interface is the same vtable as the class itself.
if let Some(interface) = is_default_async(&interfaces) {
let interface_name = writer.type_name(&interface.ty);

return quote! {
#features
pub type #name = #interface_name;
};
}

let mut methods = quote! {};
let mut method_names = MethodNames::new();

let cfg = cfg::type_def_cfg(writer, def, &[]);
let features = writer.cfg_features(&cfg);

for interface in &interfaces {
if let metadata::Type::TypeDef(def, generics) = &interface.ty {
let mut virtual_names = MethodNames::new();
Expand Down Expand Up @@ -132,14 +144,6 @@ fn gen_class(writer: &Writer, def: metadata::TypeDef) -> TokenStream {
true,
));
tokens.combine(&writer.runtime_name_trait(def, &[], &name, &TokenStream::new(), &features));
tokens.combine(&writer.async_get(
def,
&[],
&name,
&TokenStream::new(),
&TokenStream::new(),
&features,
));
tokens.combine(&iterators::writer(
writer,
def,
Expand Down Expand Up @@ -251,3 +255,22 @@ fn type_is_exclusive(ty: &metadata::Type) -> bool {
_ => false,
}
}

fn is_default_async(interfaces: &[metadata::Interface]) -> Option<&metadata::Interface> {
interfaces.iter().find(|interface| {
if interface.kind == metadata::InterfaceKind::Default {
if let metadata::Type::TypeDef(def, _) = interface.ty {
if matches!(
def.type_name(),
metadata::TypeName::IAsyncAction
| metadata::TypeName::IAsyncActionWithProgress
| metadata::TypeName::IAsyncOperation
| metadata::TypeName::IAsyncOperationWithProgress
) {
return true;
}
}
}
false
})
}
8 changes: 0 additions & 8 deletions crates/libs/bindgen/src/rust/interfaces.rs
Original file line number Diff line number Diff line change
Expand Up @@ -201,14 +201,6 @@ fn gen_win_interface(writer: &Writer, def: metadata::TypeDef) -> TokenStream {
}
});

tokens.combine(&writer.async_get(
def,
generics,
&ident,
&constraints,
&phantoms,
&features,
));
tokens.combine(&iterators::writer(
writer,
def,
Expand Down
77 changes: 0 additions & 77 deletions crates/libs/bindgen/src/rust/writer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -634,72 +634,7 @@ impl Writer {
quote! {}
}
}
pub fn async_get(
&self,
def: metadata::TypeDef,
generics: &[metadata::Type],
ident: &TokenStream,
constraints: &TokenStream,
_phantoms: &TokenStream,
features: &TokenStream,
) -> TokenStream {
let mut kind = type_def_async_kind(def);
let mut async_generics = generics.to_vec();

if kind == metadata::AsyncKind::None {
for interface in def.interface_impls().map(move |imp| imp.ty(generics)) {
if let metadata::Type::TypeDef(interface_def, interface_generics) = &interface {
kind = type_def_async_kind(*interface_def);
if kind != metadata::AsyncKind::None {
async_generics = interface_generics.to_vec();
break;
}
}
}
}

if kind == metadata::AsyncKind::None {
quote! {}
} else {
let return_type = match kind {
metadata::AsyncKind::Operation | metadata::AsyncKind::OperationWithProgress => {
self.type_name(&async_generics[0])
}
_ => quote! { () },
};

let handler = match kind {
metadata::AsyncKind::Action => quote! { AsyncActionCompletedHandler },
metadata::AsyncKind::ActionWithProgress => {
quote! { AsyncActionWithProgressCompletedHandler }
}
metadata::AsyncKind::Operation => quote! { AsyncOperationCompletedHandler },
metadata::AsyncKind::OperationWithProgress => {
quote! { AsyncOperationWithProgressCompletedHandler }
}
rest => unimplemented!("{rest:?}"),
};

let namespace = self.namespace("Windows.Foundation");

quote! {
#features
impl<#constraints> #ident {
pub fn get(&self) -> windows_core::Result<#return_type> {
if self.Status()? == #namespace AsyncStatus::Started {
let (_waiter, signaler) = windows_core::imp::Waiter::new()?;
self.SetCompleted(&#namespace #handler::new(move |_sender, _args| {
// Safe because the waiter will only be dropped after being signaled.
unsafe { signaler.signal(); }
Ok(())
}))?;
}
self.GetResults()
}
}
}
}
}
pub fn interface_winrt_trait(
&self,
def: metadata::TypeDef,
Expand Down Expand Up @@ -1463,18 +1398,6 @@ fn gen_const_ptrs(pointers: usize) -> TokenStream {
"*const ".repeat(pointers).into()
}

fn type_def_async_kind(row: metadata::TypeDef) -> metadata::AsyncKind {
match row.type_name() {
metadata::TypeName::IAsyncAction => metadata::AsyncKind::Action,
metadata::TypeName::IAsyncActionWithProgress => metadata::AsyncKind::ActionWithProgress,
metadata::TypeName::IAsyncOperation => metadata::AsyncKind::Operation,
metadata::TypeName::IAsyncOperationWithProgress => {
metadata::AsyncKind::OperationWithProgress
}
_ => metadata::AsyncKind::None,
}
}

fn type_def_is_agile(row: metadata::TypeDef) -> bool {
for attribute in row.attributes() {
match attribute.name() {
Expand Down
Loading

0 comments on commit 0fb1a7f

Please sign in to comment.