use super::*;
use crate::attributes::{ComClass, ComInterface, HasInterface};
use crate::raw::RawComPtr;
use crate::type_system::TypeSystemName;
use std::sync::atomic::{AtomicU32, Ordering};
pub struct ComBox<T: ComClass>
{
data: *mut ComBoxData<T>,
}
impl<T: ComClass> ComBox<T>
{
pub fn new(value: T) -> ComBox<T>
{
let cb = ComBoxData::new(value);
unsafe { ComBoxData::add_ref(&*cb) };
ComBox { data: cb }
}
unsafe fn as_comitf<I: ComInterface + ?Sized>(&self) -> ComItf<I>
where
T: HasInterface<I>,
{
let (automation_ptr, raw_ptr) = {
let vtbl = &self.as_ref().vtable_list;
let automation_ptr = match I::iid(TypeSystemName::Automation) {
Some(iid) => match <T as ComClass>::query_interface(vtbl, iid) {
Ok(itf) => itf,
Err(_) => ::std::ptr::null_mut(),
},
None => ::std::ptr::null_mut(),
};
let raw_ptr = match I::iid(TypeSystemName::Raw) {
Some(iid) => match <T as ComClass>::query_interface(vtbl, iid) {
Ok(itf) => itf,
Err(_) => ::std::ptr::null_mut(),
},
None => ::std::ptr::null_mut(),
};
(automation_ptr, raw_ptr)
};
ComItf::maybe_new(
raw::InterfacePtr::new(automation_ptr),
raw::InterfacePtr::new(raw_ptr),
)
.expect("Intercom failed to create interface pointers")
}
}
impl<T: ComClass + std::fmt::Debug> std::fmt::Debug for ComBox<T>
{
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result
{
write!(f, "ComBox(")?;
self.as_ref().fmt(f)?;
write!(f, ")")
}
}
impl<T: ComClass> Drop for ComBox<T>
{
fn drop(&mut self)
{
unsafe { ComBoxData::release(self.data) };
}
}
impl<T: ComClass> AsMut<ComBoxData<T>> for ComBox<T>
{
fn as_mut(&mut self) -> &mut ComBoxData<T>
{
unsafe { self.data.as_mut().expect("ComBox had null reference") }
}
}
impl<T: ComClass> AsRef<ComBoxData<T>> for ComBox<T>
{
fn as_ref(&self) -> &ComBoxData<T>
{
unsafe { self.data.as_ref().expect("ComBox had null reference") }
}
}
impl<I: ComInterface + ?Sized, T: HasInterface<I>> From<ComBox<T>> for ComRc<I>
{
fn from(source: ComBox<T>) -> ComRc<I>
{
unsafe {
let rc = ComRc::attach(source.as_comitf());
std::mem::forget(source);
rc
}
}
}
impl<I: ComInterface + ?Sized, T: HasInterface<I>> From<&ComBox<T>> for ComRc<I>
{
fn from(combox: &ComBox<T>) -> Self
{
unsafe { ComRc::from(&combox.as_comitf()) }
}
}
#[repr(C)]
pub struct ComBoxData<T: ComClass>
{
vtable_list: T::VTableList,
ref_count: AtomicU32,
value: T,
}
impl<T: ComClass> ComBoxData<T>
{
pub fn new(value: T) -> *mut ComBoxData<T>
{
Box::into_raw(Box::new(ComBoxData {
vtable_list: T::VTABLE,
ref_count: AtomicU32::new(0),
value,
}))
}
pub unsafe fn query_interface(this: &Self, riid: REFIID, out: *mut RawComPtr) -> raw::HRESULT
{
match T::query_interface(&this.vtable_list, riid) {
Ok(ptr) => {
*out = ptr;
Self::add_ref(this);
raw::S_OK
}
Err(e) => {
*out = std::ptr::null_mut();
e
}
}
}
pub unsafe fn add_ref(this: &Self) -> u32
{
let previous_value = this.ref_count.fetch_add(1, Ordering::Relaxed);
previous_value + 1
}
pub fn get_ref_count(&self) -> u32
{
self.ref_count.load(Ordering::Relaxed)
}
pub unsafe fn release(this: *mut Self) -> u32
{
if (*this).ref_count.load(Ordering::Relaxed) == 0 {
panic!("Attempt to release pointer with no references.");
}
let previous_value = (*this).ref_count.fetch_sub(1, Ordering::Relaxed);
let rc = previous_value - 1;
if rc == 0 {
drop(Box::from_raw(this));
}
rc
}
pub unsafe fn from_ptr<'a>(ptr: RawComPtr) -> &'a mut ComBoxData<T>
{
&mut *(ptr as *mut ComBoxData<T>)
}
pub fn vtable(ct: &ComBox<T>) -> &T::VTableList
{
unsafe { &(*ct.data).vtable_list }
}
pub unsafe fn of(value: &T) -> &ComBoxData<T>
{
let null_combox = std::ptr::null() as *const ComBoxData<T>;
let value_offset = &((*null_combox).value) as *const _ as usize;
let combox_loc = value as *const T as usize - value_offset;
&mut *(combox_loc as *mut ComBoxData<T>)
}
pub unsafe fn of_mut(value: &mut T) -> &mut ComBoxData<T>
{
let null_combox = std::ptr::null() as *const ComBoxData<T>;
let value_offset = &((*null_combox).value) as *const _ as usize;
let combox_loc = value as *mut T as usize - value_offset;
&mut *(combox_loc as *mut ComBoxData<T>)
}
#[inline]
pub unsafe fn null_vtable() -> &'static T::VTableList
{
let null_combox = std::ptr::null() as *const ComBoxData<T>;
&(*null_combox).vtable_list
}
}
impl<T> std::ops::Deref for ComBoxData<T>
where
T: ComClass,
{
type Target = T;
fn deref(&self) -> &T
{
&self.value
}
}
impl<T> std::ops::DerefMut for ComBoxData<T>
where
T: ComClass,
{
fn deref_mut(&mut self) -> &mut T
{
&mut self.value
}
}
impl<T> std::ops::Deref for ComBox<T>
where
T: ComClass,
{
type Target = T;
fn deref(&self) -> &T
{
unsafe { &(*self.data).value }
}
}
impl<T> std::ops::DerefMut for ComBox<T>
where
T: ComClass,
{
fn deref_mut(&mut self) -> &mut T
{
unsafe { &mut (*self.data).value }
}
}
impl<T: Default + ComClass> Default for ComBox<T>
{
fn default() -> Self
{
ComBox::new(T::default())
}
}