Skip to content

Commit

Permalink
Implement From<T> and From<&T> for interface hierarchies (#2779)
Browse files Browse the repository at this point in the history
  • Loading branch information
kennykerr authored Jan 8, 2024
1 parent 3999d7d commit 3ee83d5
Show file tree
Hide file tree
Showing 6 changed files with 112 additions and 15 deletions.
10 changes: 2 additions & 8 deletions crates/libs/core/src/imp/generic_factory.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,8 @@ use crate::Interface;

// A streamlined version of the IActivationFactory interface used by WinRT class factories used internally by the windows crate
// to simplify code generation. Components should implement the `IActivationFactory` interface published by the windows crate.
#[repr(transparent)]
#[derive(Clone, PartialEq, Eq)]
pub struct IGenericFactory(crate::IUnknown);
super::com_interface!(IGenericFactory, IGenericFactory_Vtbl, 0x00000035_0000_0000_c000_000000000046);
super::interface_hierarchy!(IGenericFactory, crate::IUnknown, crate::IInspectable);

impl IGenericFactory {
pub fn ActivateInstance<I: Interface>(&self) -> crate::Result<I> {
Expand All @@ -20,8 +19,3 @@ pub struct IGenericFactory_Vtbl {
pub base__: crate::IInspectable_Vtbl,
pub ActivateInstance: unsafe extern "system" fn(this: *mut std::ffi::c_void, instance: *mut *mut std::ffi::c_void) -> crate::HRESULT,
}

unsafe impl Interface for IGenericFactory {
type Vtable = IGenericFactory_Vtbl;
const IID: crate::GUID = crate::GUID::from_u128(0x00000035_0000_0000_c000_000000000046);
}
10 changes: 10 additions & 0 deletions crates/libs/core/src/imp/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,16 @@ pub fn wide_trim_end(mut wide: &[u16]) -> &[u16] {
macro_rules! interface_hierarchy {
($child:ident, $parent:ty) => {
impl ::windows_core::CanInto<$parent> for $child {}
impl ::core::convert::From<&$child> for &$parent {
fn from(value: &$child) -> Self {
unsafe { ::core::mem::transmute(value) }
}
}
impl ::core::convert::From<$child> for $parent {
fn from(value: $child) -> Self {
unsafe { ::core::mem::transmute(value) }
}
}
};
($child:ident, $first:ty, $($rest:ty),+) => {
$crate::imp::interface_hierarchy!($child, $first);
Expand Down
4 changes: 2 additions & 2 deletions crates/libs/core/src/inspectable.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@ use super::*;
#[derive(Clone, PartialEq, Eq)]
pub struct IInspectable(pub IUnknown);

interface_hierarchy!(IInspectable, IUnknown);

impl IInspectable {
/// Returns the canonical type name for the underlying object.
pub fn GetRuntimeClassName(&self) -> Result<HSTRING> {
Expand Down Expand Up @@ -42,8 +44,6 @@ unsafe impl Interface for IInspectable {
const IID: GUID = GUID::from_u128(0xaf86e2e0_b12d_4c6a_9c5a_d7aa65101e90);
}

impl CanInto<IUnknown> for IInspectable {}

impl RuntimeType for IInspectable {
const SIGNATURE: crate::imp::ConstBuffer = crate::imp::ConstBuffer::from_slice(b"cinterface(IInspectable)");
}
Expand Down
4 changes: 0 additions & 4 deletions crates/libs/core/src/unknown.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,10 +15,6 @@ pub struct IUnknown_Vtbl {
pub Release: unsafe extern "system" fn(this: *mut std::ffi::c_void) -> u32,
}

// impl TypeKind for IUnknown {
// type TypeKind = ReferenceType;
// }

unsafe impl Interface for IUnknown {
type Vtable = IUnknown_Vtbl;
const IID: GUID = GUID::from_u128(0x00000000_0000_0000_c000_000000000046);
Expand Down
2 changes: 1 addition & 1 deletion crates/tests/implement/tests/identity.rs
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,7 @@ fn identity() -> Result<()> {
assert_eq!(c.GetRuntimeClassName()?, "Windows.Foundation.IStringable");

let d: IClosable = a.cast()?;
let e: &IInspectable = std::mem::transmute(&d);
let e: &IInspectable = (&d).into();
assert_eq!(e.GetRuntimeClassName()?, "Windows.Foundation.IClosable");

let f: IInspectable = e.cast()?;
Expand Down
97 changes: 97 additions & 0 deletions crates/tests/implement/tests/identity_from.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
#![allow(non_snake_case)]

use windows::{core::*, Foundation::*};

#[implement(IStringable, IClosable)]
struct Test;

impl IStringable_Impl for Test {
fn ToString(&self) -> Result<HSTRING> {
todo!()
}
}

impl IClosable_Impl for Test {
fn Close(&self) -> Result<()> {
todo!()
}
}

// This tests that the interface_hierarchy macro correctly implement From<T> and From<&T> for interfaces.
#[test]
fn identity_from() -> Result<()> {
{
let inspectable: IInspectable = Test.into();
assert_eq!(
inspectable.GetRuntimeClassName()?,
"Windows.Foundation.IStringable"
);

let unknown = Into::<&IUnknown>::into(&inspectable);
assert_eq!(
unknown.cast::<IInspectable>()?.GetRuntimeClassName()?,
"Windows.Foundation.IStringable"
);

let unknown = Into::<IUnknown>::into(inspectable);
assert_eq!(
unknown.cast::<IInspectable>()?.GetRuntimeClassName()?,
"Windows.Foundation.IStringable"
);
}
{
let stringable: IStringable = Test.into();

let inspectable = Into::<&IInspectable>::into(&stringable);
assert_eq!(
inspectable.GetRuntimeClassName()?,
"Windows.Foundation.IStringable"
);

let inspectable = Into::<IInspectable>::into(stringable.clone());
assert_eq!(
inspectable.GetRuntimeClassName()?,
"Windows.Foundation.IStringable"
);

let unknown = Into::<&IUnknown>::into(&stringable);
assert_eq!(
unknown.cast::<IInspectable>()?.GetRuntimeClassName()?,
"Windows.Foundation.IStringable"
);

let unknown = Into::<IUnknown>::into(stringable);
assert_eq!(
unknown.cast::<IInspectable>()?.GetRuntimeClassName()?,
"Windows.Foundation.IStringable"
);
}
{
let closable: IClosable = Test.into();

let inspectable = Into::<&IInspectable>::into(&closable);
assert_eq!(
inspectable.GetRuntimeClassName()?,
"Windows.Foundation.IClosable"
);

let inspectable = Into::<IInspectable>::into(closable.clone());
assert_eq!(
inspectable.GetRuntimeClassName()?,
"Windows.Foundation.IClosable"
);

let unknown = Into::<&IUnknown>::into(&closable);
assert_eq!(
unknown.cast::<IInspectable>()?.GetRuntimeClassName()?,
"Windows.Foundation.IStringable"
);

let unknown = Into::<IUnknown>::into(closable);
assert_eq!(
unknown.cast::<IInspectable>()?.GetRuntimeClassName()?,
"Windows.Foundation.IStringable"
);
}
Ok(())
}

0 comments on commit 3ee83d5

Please sign in to comment.