Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add explicit path support to the interface macro #2976

Merged
merged 3 commits into from
Apr 8, 2024
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
27 changes: 13 additions & 14 deletions crates/libs/interface/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -341,41 +341,40 @@ impl Interface {
}

fn parent_vtable(&self) -> Option<proc_macro2::TokenStream> {
if let Some(i) = self.parent_ident() {
let i = quote::format_ident!("{}_Vtbl", i);
Some(quote!(#i))
if let Some((ident, path)) = self.parent_path().split_last() {
let ident = quote::format_ident!("{}_Vtbl", ident);
Some(quote! { #(#path::)* #ident })
} else {
None
}
}

fn parent_is_iunknown(&self) -> bool {
if let Some(ident) = self.parent_ident() {
if let Some(ident) = self.parent_path().last() {
ident == "IUnknown"
} else {
false
}
}

fn parent_ident(&self) -> Option<&syn::Ident> {
fn parent_path(&self) -> Vec<syn::Ident> {
if let Some(parent) = &self.parent {
Some(&parent.segments.last().as_ref().expect("segements should never be empty").ident)
parent.segments.iter().map(|segment| segment.ident.clone()).collect()
} else {
None
vec![]
}
}

/// Gets the parent trait constrait which is nothing if the parent is IUnknown
fn parent_trait_constraint(&self) -> proc_macro2::TokenStream {
if let Some(i) = self.parent_ident() {
if i == "IUnknown" {
return quote!();
if let Some((ident, path)) = self.parent_path().split_last() {
if ident != "IUnknown" {
let ident = quote::format_ident!("{}_Impl", ident);
return quote! { #(#path::)* #ident };
}
let i = quote::format_ident!("{}_Impl", i);
quote!(#i)
} else {
quote!()
}

quote! {}
}
}

Expand Down
39 changes: 39 additions & 0 deletions crates/tests/interface/tests/no_use.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
#![allow(non_snake_case)]

// This is a variant of the interface_core/no_use.rs test for use with more complex paths provided by the windows crate.

#[windows::core::interface("BD1AE5E0-A6AE-11CE-BD37-504200C10000")]
unsafe trait ITestPersistMemory: windows::Win32::System::Com::IPersist {
unsafe fn IsDirty(&self) -> windows::core::HRESULT;
}

#[windows::core::implement(ITestPersistMemory, windows::Win32::System::Com::IPersist)]
struct Test;

impl windows::Win32::System::Com::IPersist_Impl for Test {
fn GetClassID(&self) -> windows::core::Result<windows::core::GUID> {
Ok("CEE1D356-0860-4262-90D4-C77423F0E352".into())
}
}

impl ITestPersistMemory_Impl for Test {
unsafe fn IsDirty(&self) -> windows::core::HRESULT {
windows::Win32::Foundation::S_FALSE
}
}

#[test]
fn test() -> windows::core::Result<()> {
unsafe {
let p: windows::Win32::System::Com::IPersist = Test.into();
assert_eq!(
p.GetClassID()?,
"CEE1D356-0860-4262-90D4-C77423F0E352".into()
);

let m: ITestPersistMemory = windows_core::Interface::cast(&p)?;
assert_eq!(m.IsDirty(), windows::Win32::Foundation::S_FALSE);

Ok(())
}
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
#![allow(non_snake_case)]

// This tests uses `windows_core` via an asterisk to test that the interface/implement macros support this mode
// as opposed to no_use.rs which tests the opposite.

use windows_core::*;

#[interface("72cd87fa-9c99-42e0-8986-84a76f08fc5a")]
Expand Down
26 changes: 26 additions & 0 deletions crates/tests/interface_core/tests/no_use.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
#![allow(non_snake_case)]

// This tests uses `windows_core` explicitly to test that the interface/implement macros support this mode
// as opposed to asterisk_use.rs which tests the opposite.

#[windows_core::interface("72cd87fa-9c99-42e0-8986-84a76f08fc5a")]
unsafe trait ITest: windows_core::IUnknown {
unsafe fn Test(&self) -> windows_core::HRESULT;
}

#[windows_core::implement(ITest)]
struct Test;

impl ITest_Impl for Test {
unsafe fn Test(&self) -> windows_core::HRESULT {
windows_core::HRESULT(123)
}
}

#[test]
fn test() {
unsafe {
let test: ITest = Test.into();
assert_eq!(test.Test(), windows_core::HRESULT(123));
}
}