diff options
Diffstat (limited to 'third_party/rust/dwrote/src/com_helpers.rs')
-rw-r--r-- | third_party/rust/dwrote/src/com_helpers.rs | 127 |
1 files changed, 127 insertions, 0 deletions
diff --git a/third_party/rust/dwrote/src/com_helpers.rs b/third_party/rust/dwrote/src/com_helpers.rs new file mode 100644 index 0000000000..b4bcf16641 --- /dev/null +++ b/third_party/rust/dwrote/src/com_helpers.rs @@ -0,0 +1,127 @@ +// This is only handy for implementing a single-interface-implementing IUnknown. + +macro_rules! implement_iunknown { + ($interface:ident, $typ:ident) => { + IUnknownVtbl { + QueryInterface: { + #[allow(non_snake_case)] + unsafe extern "system" fn QueryInterface( + unknown_this: *mut IUnknown, + riid: REFIID, + ppv_object: *mut *mut c_void, + ) -> HRESULT { + use $crate::winapi::Interface; + let this = if $crate::winapi::shared::guiddef::IsEqualGUID( + &*riid, + &$interface::uuidof(), + ) { + mem::transmute(unknown_this) + } else if $crate::winapi::shared::guiddef::IsEqualGUID( + &*riid, + &IUnknown::uuidof(), + ) { + mem::transmute(unknown_this) + } else { + return $crate::winapi::shared::winerror::E_NOINTERFACE; + }; + + (*unknown_this).AddRef(); + *ppv_object = this; + return S_OK; + } + QueryInterface + }, + AddRef: { + unsafe extern "system" fn AddRef(unknown_this: *mut IUnknown) -> ULONG { + let this = $typ::from_interface(unknown_this); + let count = this.refcount.fetch_add(1, atomic::Ordering::Relaxed) + 1; + count as ULONG + } + AddRef + }, + Release: { + unsafe extern "system" fn Release(unknown_this: *mut IUnknown) -> ULONG { + let this = $typ::from_interface(unknown_this); + let count = this.refcount.fetch_sub(1, atomic::Ordering::Release) - 1; + if count == 0 { + <$typ as Com<$interface>>::destroy(unknown_this as *mut $interface); + } + count as ULONG + } + Release + }, + } + }; + (static $interface:ident, $typ:ident) => { + IUnknownVtbl { + QueryInterface: { + #[allow(non_snake_case)] + unsafe extern "system" fn QueryInterface( + unknown_this: *mut IUnknown, + riid: REFIID, + ppvObject: *mut *mut $crate::winapi::ctypes::c_void, + ) -> HRESULT { + use $crate::winapi::Interface; + let this = if $crate::winapi::shared::guiddef::IsEqualGUID( + &*riid, + &$interface::uuidof(), + ) { + mem::transmute(unknown_this) + } else if $crate::winapi::shared::guiddef::IsEqualGUID( + &*riid, + &IUnknown::uuidof(), + ) { + mem::transmute(unknown_this) + } else { + return $crate::winapi::shared::winerror::E_NOINTERFACE; + }; + + (*unknown_this).AddRef(); + *ppvObject = this; + return S_OK; + } + QueryInterface + }, + AddRef: { + // FIXME(pcwalton): Uh? Maybe we should actually reference count? + #[allow(non_snake_case)] + unsafe extern "system" fn AddRef(_: *mut IUnknown) -> ULONG { + 1 + } + AddRef + }, + Release: { + #[allow(non_snake_case)] + unsafe extern "system" fn Release(_: *mut IUnknown) -> ULONG { + 1 + } + Release + }, + } + }; +} + +#[repr(C)] +pub struct ComRepr<Type, Vtbl>(*const Vtbl, Type); + +pub trait Com<Interface> +where + Self: Sized, +{ + type Vtbl: 'static; + + fn vtbl() -> &'static Self::Vtbl; + + fn into_interface(self) -> *mut Interface { + let com = Box::new(ComRepr(Self::vtbl(), self)); + Box::into_raw(com) as *mut Interface + } + + unsafe fn from_interface<'a>(thing: *mut Interface) -> &'a mut Self { + &mut (*(thing as *mut ComRepr<Self, Self::Vtbl>)).1 + } + + unsafe fn destroy(thing: *mut Interface) { + Box::from_raw(thing as *mut ComRepr<Self, Self::Vtbl>); + } +} |