use crate::sys::{E_NOINTERFACE, E_POINTER, FAILED};
use crate::{interfaces::IUnknown, ComInterface, ComRc, IID};
use std::ffi::c_void;
use std::marker::PhantomData;
use std::ptr::NonNull;
#[repr(transparent)]
pub struct ComPtr<T: ComInterface + ?Sized> {
ptr: NonNull<*mut <T as ComInterface>::VTable>,
phantom: PhantomData<T>,
}
impl<T: ComInterface + ?Sized> ComPtr<T> {
pub unsafe fn new(ptr: *mut *mut <T as ComInterface>::VTable) -> ComPtr<T> {
ComPtr {
ptr: NonNull::new(ptr).expect("ComPtr's ptr was null"),
phantom: PhantomData,
}
}
pub fn upgrade(self) -> ComRc<T> {
ComRc::new(self)
}
pub fn as_raw(&self) -> *mut *mut <T as ComInterface>::VTable {
self.ptr.as_ptr()
}
pub fn get_interface<I: ComInterface + ?Sized>(&self) -> Option<ComPtr<I>> {
let mut ppv = std::ptr::null_mut::<c_void>();
let hr = unsafe { self.query_interface(&I::IID as *const IID, &mut ppv) };
if FAILED(hr) {
assert!(
hr == E_NOINTERFACE || hr == E_POINTER,
"QueryInterface returned non-standard error"
);
return None;
}
assert!(!ppv.is_null(), "The pointer to the interface returned from a successful call to QueryInterface was null");
Some(unsafe { ComPtr::new(ppv as *mut *mut _) })
}
}
impl<T: ComInterface + ?Sized> std::convert::From<ComRc<T>> for ComPtr<T> {
fn from(rc: crate::ComRc<T>) -> Self {
let result = unsafe { ComPtr::new(rc.as_raw()) };
std::mem::forget(rc);
result
}
}
impl<T: ComInterface + ?Sized> Clone for ComPtr<T> {
fn clone(&self) -> Self {
unsafe {
self.add_ref();
ComPtr::new(self.ptr.as_ptr())
}
}
}