use crate::imp::Box;
use crate::{AsImpl, IUnknown, IUnknownImpl, Interface, InterfaceRef};
use core::any::Any;
use core::borrow::Borrow;
use core::ops::Deref;
use core::ptr::NonNull;
pub trait ComObjectInner: Sized {
type Outer: IUnknownImpl<Impl = Self>;
fn into_object(self) -> ComObject<Self>;
}
pub trait ComObjectInterface<I: Interface> {
fn as_interface_ref(&self) -> InterfaceRef<'_, I>;
}
#[repr(transparent)]
pub struct ComObject<T: ComObjectInner> {
ptr: NonNull<T::Outer>,
}
impl<T: ComObjectInner> ComObject<T> {
pub fn new(value: T) -> Self {
T::into_object(value)
}
pub unsafe fn from_raw(ptr: NonNull<T::Outer>) -> Self {
Self { ptr }
}
#[inline(always)]
pub fn get(&self) -> &T {
self.get_box().get_impl()
}
#[inline(always)]
fn get_box(&self) -> &T::Outer {
unsafe { self.ptr.as_ref() }
}
#[inline(always)]
pub fn get_mut(&mut self) -> Option<&mut T> {
if self.is_reference_count_one() {
unsafe { Some(self.ptr.as_mut().get_impl_mut()) }
} else {
None
}
}
#[inline(always)]
pub fn take(self) -> Result<T, Self> {
if self.is_reference_count_one() {
let outer_box: Box<T::Outer> = unsafe { core::mem::transmute(self) };
Ok(outer_box.into_inner())
} else {
Err(self)
}
}
#[inline(always)]
pub fn cast<I: Interface>(&self) -> windows_core::Result<I>
where
T::Outer: ComObjectInterface<IUnknown>,
{
let unknown = self.as_interface::<IUnknown>();
unknown.cast()
}
#[inline(always)]
pub fn as_interface<I: Interface>(&self) -> InterfaceRef<'_, I>
where
T::Outer: ComObjectInterface<I>,
{
self.get_box().as_interface_ref()
}
#[inline(always)]
pub fn to_interface<I: Interface>(&self) -> I
where
T::Outer: ComObjectInterface<I>,
{
self.as_interface::<I>().to_owned()
}
#[inline(always)]
pub fn into_interface<I: Interface>(self) -> I
where
T::Outer: ComObjectInterface<I>,
{
unsafe {
let raw = self.get_box().as_interface_ref().as_raw();
core::mem::forget(self);
I::from_raw(raw)
}
}
pub fn cast_from<I>(interface: &I) -> crate::Result<Self>
where
I: Interface,
T::Outer: Any + 'static + IUnknownImpl<Impl = T>,
{
interface.cast_object()
}
}
impl<T: ComObjectInner + Default> Default for ComObject<T> {
fn default() -> Self {
Self::new(T::default())
}
}
impl<T: ComObjectInner> Drop for ComObject<T> {
fn drop(&mut self) {
unsafe {
T::Outer::Release(self.ptr.as_ptr());
}
}
}
impl<T: ComObjectInner> Clone for ComObject<T> {
#[inline(always)]
fn clone(&self) -> Self {
unsafe {
self.ptr.as_ref().AddRef();
Self { ptr: self.ptr }
}
}
}
impl<T: ComObjectInner> AsRef<T> for ComObject<T>
where
IUnknown: From<T> + AsImpl<T>,
{
#[inline(always)]
fn as_ref(&self) -> &T {
self.get()
}
}
impl<T: ComObjectInner> Deref for ComObject<T> {
type Target = T::Outer;
#[inline(always)]
fn deref(&self) -> &Self::Target {
self.get_box()
}
}
impl<T: ComObjectInner> From<T> for ComObject<T> {
fn from(value: T) -> ComObject<T> {
ComObject::new(value)
}
}
impl<T: ComObjectInner + core::hash::Hash> core::hash::Hash for ComObject<T> {
fn hash<H: core::hash::Hasher>(&self, state: &mut H) {
self.get().hash(state);
}
}
unsafe impl<T: ComObjectInner + Send> Send for ComObject<T> {}
unsafe impl<T: ComObjectInner + Sync> Sync for ComObject<T> {}
impl<T: ComObjectInner + PartialEq> PartialEq for ComObject<T> {
fn eq(&self, other: &ComObject<T>) -> bool {
let inner_self: &T = self.get();
let other_self: &T = other.get();
inner_self == other_self
}
}
impl<T: ComObjectInner + Eq> Eq for ComObject<T> {}
impl<T: ComObjectInner + PartialOrd> PartialOrd for ComObject<T> {
fn partial_cmp(&self, other: &Self) -> Option<core::cmp::Ordering> {
let inner_self: &T = self.get();
let other_self: &T = other.get();
<T as PartialOrd>::partial_cmp(inner_self, other_self)
}
}
impl<T: ComObjectInner + Ord> Ord for ComObject<T> {
fn cmp(&self, other: &Self) -> core::cmp::Ordering {
let inner_self: &T = self.get();
let other_self: &T = other.get();
<T as Ord>::cmp(inner_self, other_self)
}
}
impl<T: ComObjectInner + core::fmt::Debug> core::fmt::Debug for ComObject<T> {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
<T as core::fmt::Debug>::fmt(self.get(), f)
}
}
impl<T: ComObjectInner + core::fmt::Display> core::fmt::Display for ComObject<T> {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
<T as core::fmt::Display>::fmt(self.get(), f)
}
}
impl<T: ComObjectInner> Borrow<T> for ComObject<T> {
fn borrow(&self) -> &T {
self.get()
}
}