Skip to content

Commit

Permalink
static event test/sample
Browse files Browse the repository at this point in the history
  • Loading branch information
kennykerr committed Dec 13, 2024
1 parent fa2b63a commit 08cf3e6
Show file tree
Hide file tree
Showing 6 changed files with 256 additions and 7 deletions.
2 changes: 1 addition & 1 deletion crates/libs/core/src/event.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ impl<T: Interface> Default for Event<T> {

impl<T: Interface> Event<T> {
/// Creates a new, empty `Event<T>`.
pub fn new() -> Self {
pub const fn new() -> Self {
Self {
delegates: RwLock::new(None),
}
Expand Down
128 changes: 128 additions & 0 deletions crates/tests/winrt/events/src/bindings.rs
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,47 @@ impl Class {
.ok()
}
}
pub fn StaticSignal(value: i32) -> windows_core::Result<i32> {
Self::IClassStatics(|this| unsafe {
let mut result__ = core::mem::zeroed();
(windows_core::Interface::vtable(this).StaticSignal)(
windows_core::Interface::as_raw(this),
value,
&mut result__,
)
.map(|| result__)
})
}
pub fn StaticEvent<P0>(handler: P0) -> windows_core::Result<i64>
where
P0: windows_core::Param<windows::Foundation::EventHandler<i32>>,
{
Self::IClassStatics(|this| unsafe {
let mut result__ = core::mem::zeroed();
(windows_core::Interface::vtable(this).StaticEvent)(
windows_core::Interface::as_raw(this),
handler.param().abi(),
&mut result__,
)
.map(|| result__)
})
}
pub fn RemoveStaticEvent(token: i64) -> windows_core::Result<()> {
Self::IClassStatics(|this| unsafe {
(windows_core::Interface::vtable(this).RemoveStaticEvent)(
windows_core::Interface::as_raw(this),
token,
)
.ok()
})
}
fn IClassStatics<R, F: FnOnce(&IClassStatics) -> windows_core::Result<R>>(
callback: F,
) -> windows_core::Result<R> {
static SHARED: windows_core::imp::FactoryCache<Class, IClassStatics> =
windows_core::imp::FactoryCache::new();
SHARED.call(callback)
}
}
impl windows_core::RuntimeType for Class {
const SIGNATURE: windows_core::imp::ConstBuffer =
Expand Down Expand Up @@ -152,3 +193,90 @@ pub struct IClass_Vtbl {
pub RemoveEvent:
unsafe extern "system" fn(*mut core::ffi::c_void, i64) -> windows_core::HRESULT,
}
windows_core::imp::define_interface!(
IClassStatics,
IClassStatics_Vtbl,
0x47439b4f_f0b4_5a72_8777_4d60e34ec843
);
impl windows_core::RuntimeType for IClassStatics {
const SIGNATURE: windows_core::imp::ConstBuffer =
windows_core::imp::ConstBuffer::for_interface::<Self>();
}
impl windows_core::RuntimeName for IClassStatics {
const NAME: &'static str = "test_events.IClassStatics";
}
pub trait IClassStatics_Impl: windows_core::IUnknownImpl {
fn StaticSignal(&self, value: i32) -> windows_core::Result<i32>;
fn StaticEvent(
&self,
handler: windows_core::Ref<'_, windows::Foundation::EventHandler<i32>>,
) -> windows_core::Result<i64>;
fn RemoveStaticEvent(&self, token: i64) -> windows_core::Result<()>;
}
impl IClassStatics_Vtbl {
pub const fn new<Identity: IClassStatics_Impl, const OFFSET: isize>() -> Self {
unsafe extern "system" fn StaticSignal<
Identity: IClassStatics_Impl,
const OFFSET: isize,
>(
this: *mut core::ffi::c_void,
value: i32,
result__: *mut i32,
) -> windows_core::HRESULT {
let this: &Identity = &*((this as *const *const ()).offset(OFFSET) as *const Identity);
match IClassStatics_Impl::StaticSignal(this, value) {
Ok(ok__) => {
result__.write(core::mem::transmute_copy(&ok__));
windows_core::HRESULT(0)
}
Err(err) => err.into(),
}
}
unsafe extern "system" fn StaticEvent<Identity: IClassStatics_Impl, const OFFSET: isize>(
this: *mut core::ffi::c_void,
handler: *mut core::ffi::c_void,
result__: *mut i64,
) -> windows_core::HRESULT {
let this: &Identity = &*((this as *const *const ()).offset(OFFSET) as *const Identity);
match IClassStatics_Impl::StaticEvent(this, core::mem::transmute_copy(&handler)) {
Ok(ok__) => {
result__.write(core::mem::transmute_copy(&ok__));
windows_core::HRESULT(0)
}
Err(err) => err.into(),
}
}
unsafe extern "system" fn RemoveStaticEvent<
Identity: IClassStatics_Impl,
const OFFSET: isize,
>(
this: *mut core::ffi::c_void,
token: i64,
) -> windows_core::HRESULT {
let this: &Identity = &*((this as *const *const ()).offset(OFFSET) as *const Identity);
IClassStatics_Impl::RemoveStaticEvent(this, token).into()
}
Self {
base__: windows_core::IInspectable_Vtbl::new::<Identity, IClassStatics, OFFSET>(),
StaticSignal: StaticSignal::<Identity, OFFSET>,
StaticEvent: StaticEvent::<Identity, OFFSET>,
RemoveStaticEvent: RemoveStaticEvent::<Identity, OFFSET>,
}
}
pub fn matches(iid: &windows_core::GUID) -> bool {
iid == &<IClassStatics as windows_core::Interface>::IID
}
}
#[repr(C)]
pub struct IClassStatics_Vtbl {
pub base__: windows_core::IInspectable_Vtbl,
pub StaticSignal:
unsafe extern "system" fn(*mut core::ffi::c_void, i32, *mut i32) -> windows_core::HRESULT,
pub StaticEvent: unsafe extern "system" fn(
*mut core::ffi::c_void,
*mut core::ffi::c_void,
*mut i64,
) -> windows_core::HRESULT,
pub RemoveStaticEvent:
unsafe extern "system" fn(*mut core::ffi::c_void, i64) -> windows_core::HRESULT,
}
39 changes: 33 additions & 6 deletions crates/tests/winrt/events/src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,22 +1,49 @@
mod bindings;
use windows::{core::*, Foundation::*, Win32::Foundation::*, Win32::System::WinRT::*};

use windows::{core::*, Win32::Foundation::*, Win32::System::WinRT::*};
static CLASS_FACTORY: StaticComObject<ClassFactory> = ClassFactory::new().into_static();

#[no_mangle]
unsafe extern "system" fn DllGetActivationFactory(
name: Ref<HSTRING>,
factory: OutRef<IActivationFactory>,
) -> HRESULT {
if *name == "test_events.Class" {
factory.write(Some(ClassFactory.into())).into()
factory.write(Some(CLASS_FACTORY.to_interface())).into()
} else {
_ = factory.write(None);
CLASS_E_CLASSNOTAVAILABLE
}
}

#[implement(IActivationFactory)]
struct ClassFactory;
#[implement(IActivationFactory, bindings::IClassStatics)]
struct ClassFactory(Event<EventHandler<i32>>);

impl ClassFactory {
const fn new() -> Self {
Self(Event::new())
}
}

impl bindings::IClassStatics_Impl for ClassFactory_Impl {
fn StaticSignal(&self, value: i32) -> Result<i32> {
let mut counter = 0;
self.0.call(|delegate| {
counter += 1;
delegate.Invoke(self.as_interface(), value)
});
Ok(counter)
}

fn StaticEvent(&self, handler: Ref<EventHandler<i32>>) -> Result<i64> {
self.0.add(handler.unwrap())
}

fn RemoveStaticEvent(&self, token: i64) -> Result<()> {
self.0.remove(token);
Ok(())
}
}

impl IActivationFactory_Impl for ClassFactory_Impl {
fn ActivateInstance(&self) -> Result<IInspectable> {
Expand All @@ -25,7 +52,7 @@ impl IActivationFactory_Impl for ClassFactory_Impl {
}

#[implement(bindings::Class)]
struct Class(Event<windows::Foundation::TypedEventHandler<bindings::Class, i32>>);
struct Class(Event<TypedEventHandler<bindings::Class, i32>>);

impl bindings::IClass_Impl for Class_Impl {
fn Signal(&self, value: i32) -> Result<i32> {
Expand All @@ -39,7 +66,7 @@ impl bindings::IClass_Impl for Class_Impl {

fn Event(
&self,
handler: Ref<windows::Foundation::TypedEventHandler<bindings::Class, i32>>,
handler: Ref<TypedEventHandler<bindings::Class, i32>>,
) -> windows_core::Result<i64> {
self.0.add(handler.unwrap())
}
Expand Down
3 changes: 3 additions & 0 deletions crates/tests/winrt/events/src/metadata.idl
Original file line number Diff line number Diff line change
Expand Up @@ -6,5 +6,8 @@ namespace test_events

Int32 Signal(Int32 value);
event Windows.Foundation.TypedEventHandler<Class, Int32> Event;

static Int32 StaticSignal(Int32 value);
static event Windows.Foundation.EventHandler<Int32> StaticEvent;
}
}
63 changes: 63 additions & 0 deletions crates/tests/winrt/events_client/src/bindings.rs
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,47 @@ impl Class {
.ok()
}
}
pub fn StaticSignal(value: i32) -> windows_core::Result<i32> {
Self::IClassStatics(|this| unsafe {
let mut result__ = core::mem::zeroed();
(windows_core::Interface::vtable(this).StaticSignal)(
windows_core::Interface::as_raw(this),
value,
&mut result__,
)
.map(|| result__)
})
}
pub fn StaticEvent<P0>(handler: P0) -> windows_core::Result<i64>
where
P0: windows_core::Param<windows::Foundation::EventHandler<i32>>,
{
Self::IClassStatics(|this| unsafe {
let mut result__ = core::mem::zeroed();
(windows_core::Interface::vtable(this).StaticEvent)(
windows_core::Interface::as_raw(this),
handler.param().abi(),
&mut result__,
)
.map(|| result__)
})
}
pub fn RemoveStaticEvent(token: i64) -> windows_core::Result<()> {
Self::IClassStatics(|this| unsafe {
(windows_core::Interface::vtable(this).RemoveStaticEvent)(
windows_core::Interface::as_raw(this),
token,
)
.ok()
})
}
fn IClassStatics<R, F: FnOnce(&IClassStatics) -> windows_core::Result<R>>(
callback: F,
) -> windows_core::Result<R> {
static SHARED: windows_core::imp::FactoryCache<Class, IClassStatics> =
windows_core::imp::FactoryCache::new();
SHARED.call(callback)
}
}
impl windows_core::RuntimeType for Class {
const SIGNATURE: windows_core::imp::ConstBuffer =
Expand Down Expand Up @@ -93,3 +134,25 @@ pub struct IClass_Vtbl {
pub RemoveEvent:
unsafe extern "system" fn(*mut core::ffi::c_void, i64) -> windows_core::HRESULT,
}
windows_core::imp::define_interface!(
IClassStatics,
IClassStatics_Vtbl,
0x47439b4f_f0b4_5a72_8777_4d60e34ec843
);
impl windows_core::RuntimeType for IClassStatics {
const SIGNATURE: windows_core::imp::ConstBuffer =
windows_core::imp::ConstBuffer::for_interface::<Self>();
}
#[repr(C)]
pub struct IClassStatics_Vtbl {
pub base__: windows_core::IInspectable_Vtbl,
pub StaticSignal:
unsafe extern "system" fn(*mut core::ffi::c_void, i32, *mut i32) -> windows_core::HRESULT,
pub StaticEvent: unsafe extern "system" fn(
*mut core::ffi::c_void,
*mut core::ffi::c_void,
*mut i64,
) -> windows_core::HRESULT,
pub RemoveStaticEvent:
unsafe extern "system" fn(*mut core::ffi::c_void, i64) -> windows_core::HRESULT,
}
28 changes: 28 additions & 0 deletions crates/tests/winrt/events_client/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ fn test() -> Result<()> {
assert_eq!(0, class.Signal(3)?);

class.Event(&TypedEventHandler::new(
// TODO: ideally generics also use Ref<T> here
move |sender: &Option<Class>, args: &i32| {
assert_eq!(sender.as_ref().unwrap(), class);
assert_eq!(*args, 4);
Expand All @@ -44,3 +45,30 @@ fn test() -> Result<()> {
assert_eq!(2, class.Signal(4)?);
Ok(())
}

#[test]
fn test_static() -> Result<()> {
assert_eq!(0, Class::StaticSignal(1)?);

let token = Class::StaticEvent(&EventHandler::new(move |_, args| {
assert_eq!(*args, 2);
Ok(())
}))?;

assert_eq!(1, Class::StaticSignal(2)?);
Class::RemoveStaticEvent(token)?;
assert_eq!(0, Class::StaticSignal(3)?);

Class::StaticEvent(&EventHandler::new(move |_, args| {
assert_eq!(*args, 4);
Ok(())
}))?;

Class::StaticEvent(&EventHandler::new(move |_, args| {
assert_eq!(*args, 4);
Ok(())
}))?;

assert_eq!(2, Class::StaticSignal(4)?);
Ok(())
}

0 comments on commit 08cf3e6

Please sign in to comment.