use core::ffi::c_void;
use core::fmt;
use core::marker::PhantomData;
use core::mem::ManuallyDrop;
use core::ops::Deref;
use core::panic::{RefUnwindSafe, UnwindSafe};
use core::ptr::NonNull;
use crate::{ConcreteType, Type};
mod forwarding_impls;
use CFRetained as Retained;
#[cfg_attr(
not(feature = "objc2"),
doc = "[`objc2::rc::Retained`]: #objc2-not-available"
)]
#[repr(transparent)]
#[doc(alias = "id")]
#[doc(alias = "Retained")]
#[doc(alias = "objc2::rc::Retained")]
#[cfg_attr(
feature = "unstable-coerce-pointee",
derive(std::marker::CoercePointee)
)]
pub struct CFRetained<T: ?Sized> {
ptr: NonNull<T>,
item: PhantomData<T>,
notunwindsafe: PhantomData<&'static mut ()>,
}
impl<T: ?Sized + Type> CFRetained<T> {
#[inline]
pub unsafe fn from_raw(ptr: NonNull<T>) -> Self {
Self {
ptr,
item: PhantomData,
notunwindsafe: PhantomData,
}
}
#[inline]
pub fn into_raw(this: Self) -> NonNull<T> {
ManuallyDrop::new(this).ptr
}
#[inline]
pub fn as_ptr(this: &Self) -> NonNull<T> {
this.ptr
}
#[inline]
pub unsafe fn cast_unchecked<U: Type>(this: Self) -> CFRetained<U> {
let ptr = ManuallyDrop::new(this).ptr.cast();
unsafe { CFRetained::from_raw(ptr) }
}
}
impl<T: Type> CFRetained<T> {
#[cfg_attr(
feature = "CFBase",
doc = "[`CFType::downcast_ref`]: crate::CFType::downcast_ref"
)]
#[cfg_attr(
not(feature = "CFBase"),
doc = "[`CFType::downcast_ref`]: #CFType-not-available"
)]
#[doc(alias = "CFGetTypeID")]
pub fn downcast<U: ConcreteType>(self) -> Result<CFRetained<U>, Self>
where
T: 'static,
{
extern "C-unwind" {
#[allow(clashing_extern_declarations)]
fn CFGetTypeID(cf: *const c_void) -> crate::__cf_macro_helpers::CFTypeID;
}
let ptr: *const c_void = self.ptr.as_ptr().cast();
if unsafe { CFGetTypeID(ptr) } == U::type_id() {
Ok(unsafe { Self::cast_unchecked::<U>(self) })
} else {
Err(self)
}
}
#[doc(alias = "CFRetain")]
#[inline]
pub unsafe fn retain(ptr: NonNull<T>) -> Self {
extern "C-unwind" {
fn CFRetain(cf: *mut c_void) -> *mut c_void;
}
let res: *mut T = unsafe { CFRetain(ptr.as_ptr().cast()) }.cast();
let res = unsafe { NonNull::new_unchecked(res) };
unsafe { Self::from_raw(res) }
}
#[doc(alias = "CFAutorelease")]
#[must_use = "if you don't intend to use the object any more, drop it as usual instead"]
#[inline]
pub fn autorelease_ptr(this: Self) -> *mut T {
extern "C-unwind" {
fn CFAutorelease(cf: *mut c_void) -> *mut c_void;
}
let ptr = Self::into_raw(this);
unsafe { CFAutorelease(ptr.as_ptr().cast()) }.cast()
}
}
impl<T: Type> Clone for CFRetained<T> {
#[doc(alias = "CFRetain")]
#[doc(alias = "retain")]
#[inline]
fn clone(&self) -> Self {
self.retain()
}
}
impl<T: ?Sized> Drop for CFRetained<T> {
#[doc(alias = "CFRelease")]
#[doc(alias = "release")]
#[inline]
fn drop(&mut self) {
extern "C-unwind" {
fn CFRelease(cf: *mut c_void);
}
unsafe { CFRelease(self.ptr.as_ptr().cast()) };
}
}
impl<T: ?Sized> Deref for CFRetained<T> {
type Target = T;
#[inline]
fn deref(&self) -> &T {
unsafe { self.ptr.as_ref() }
}
}
impl<T: ?Sized> fmt::Pointer for CFRetained<T> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
fmt::Pointer::fmt(&self.ptr.as_ptr(), f)
}
}
impl<T: ?Sized + AsRef<U>, U: Type> From<&T> for CFRetained<U> {
#[inline]
fn from(obj: &T) -> Self {
obj.as_ref().retain()
}
}
#[cfg(feature = "CFBase")]
impl<T: ?Sized + ConcreteType + 'static> From<CFRetained<T>> for CFRetained<crate::CFType> {
#[inline]
fn from(obj: CFRetained<T>) -> Self {
unsafe { CFRetained::cast_unchecked(obj) }
}
}
#[cfg(feature = "objc2")]
impl<T: ?Sized + Type + objc2::Message> From<objc2::rc::Retained<T>> for CFRetained<T> {
#[inline]
fn from(obj: objc2::rc::Retained<T>) -> Self {
let ptr = objc2::rc::Retained::into_raw(obj);
let ptr = NonNull::new(ptr).unwrap();
unsafe { Self::from_raw(ptr) }
}
}
#[cfg(feature = "objc2")]
impl<T: ?Sized + objc2::Message> From<CFRetained<T>> for objc2::rc::Retained<T> {
#[inline]
fn from(obj: CFRetained<T>) -> Self {
let ptr = ManuallyDrop::new(obj).ptr;
unsafe { Self::from_raw(ptr.as_ptr()) }.unwrap()
}
}
unsafe impl<T: ?Sized + Sync + Send> Send for CFRetained<T> {}
unsafe impl<T: ?Sized + Sync + Send> Sync for CFRetained<T> {}
impl<T: ?Sized> Unpin for CFRetained<T> {}
impl<T: ?Sized + RefUnwindSafe> RefUnwindSafe for CFRetained<T> {}
impl<T: ?Sized + RefUnwindSafe> UnwindSafe for CFRetained<T> {}