#[cfg(feature = "objc")]
use crate::objc;
#[cfg(feature = "objc")]
use std::{
ops::{Deref, DerefMut},
ptr::NonNull,
};
pub trait Release {
unsafe fn release(&mut self);
}
pub trait Retain: Sized + Release {
fn retained(&self) -> Retained<Self>;
}
#[derive(Debug)]
#[repr(transparent)]
pub struct Allocated<T: Release + 'static>(&'static mut T);
#[derive(Debug)]
#[repr(transparent)]
pub struct Retained<T: Release + 'static>(&'static mut T);
impl<T: Release + std::error::Error> std::error::Error for Retained<T> {}
impl<T: Release + std::fmt::Display> std::fmt::Display for Retained<T> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
self.0.fmt(f)
}
}
impl<T: Retain + PartialEq> PartialEq for Retained<T> {
fn eq(&self, other: &Self) -> bool {
self.0 == other.0
}
}
impl<T: Retain + PartialEq> PartialEq<T> for Retained<T> {
fn eq(&self, other: &T) -> bool {
self.0 == other
}
}
impl<T: Retain + PartialOrd> PartialOrd for Retained<T> {
fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
self.0.partial_cmp(&other.0)
}
}
impl<T: Retain> AsRef<T> for Retained<T> {
#[inline]
fn as_ref(&self) -> &T {
self.0
}
}
impl<T: Retain> AsMut<T> for Retained<T> {
#[inline]
fn as_mut(&mut self) -> &mut T {
self.0
}
}
impl<T: Retain> Retained<T> {
#[inline]
pub fn retained(&self) -> Self {
self.0.retained()
}
}
#[cfg(feature = "objc")]
#[inline]
#[must_use]
pub unsafe fn return_opt_ar<T: objc::Obj>(val: Option<&T>) -> Option<Rar<T>> {
unsafe {
let res = objc::objc_retainAutoreleaseReturnValue(std::mem::transmute(val));
std::mem::transmute(res)
}
}
#[cfg(feature = "objc")]
impl<T: Retain> Retained<T> {
#[must_use]
pub fn autoreleased<'ar>(self) -> &'ar mut T
where
T: objc::Obj,
{
unsafe {
let res = objc::Id::autorelease(std::mem::transmute(self));
std::mem::transmute(res)
}
}
#[must_use]
pub unsafe fn return_ar(self) -> Rar<T>
where
T: objc::Obj,
{
unsafe {
let res = objc::objc_autoreleaseReturnValue(std::mem::transmute(self));
std::mem::transmute(res)
}
}
}
impl<T: Release> Drop for Allocated<T> {
#[inline]
fn drop(&mut self) {
unsafe { self.0.release() }
}
}
impl<T: Release> Drop for Retained<T> {
#[inline]
fn drop(&mut self) {
unsafe { self.0.release() }
}
}
impl<T: Release> std::ops::Deref for Retained<T> {
type Target = T;
#[inline]
fn deref(&self) -> &Self::Target {
self.0
}
}
impl<T: Release> std::ops::DerefMut for Retained<T> {
#[inline]
fn deref_mut(&mut self) -> &mut Self::Target {
self.0
}
}
#[macro_export]
macro_rules! return_ar {
($r:path) => {
return unsafe { $r.return_ar() }
};
}
#[macro_export]
macro_rules! return_opt_ar {
($r:expr) => {
return unsafe { $crate::arc::return_opt_ar($r) }
};
}
impl<T: Retain> Clone for Retained<T> {
#[inline]
fn clone(&self) -> Self {
self.retained()
}
}
#[cfg(feature = "objc")]
#[repr(transparent)]
pub struct ReturnedAutoReleased<T: objc::Obj>(NonNull<T>);
#[cfg(feature = "objc")]
impl<T: objc::Obj> Deref for ReturnedAutoReleased<T> {
type Target = T;
#[inline]
fn deref(&self) -> &Self::Target {
unsafe { self.0.as_ref() }
}
}
#[cfg(feature = "objc")]
impl<T: objc::Obj> DerefMut for ReturnedAutoReleased<T> {
#[inline]
fn deref_mut(&mut self) -> &mut Self::Target {
unsafe { self.0.as_mut() }
}
}
pub type A<T> = Allocated<T>;
pub type R<T> = Retained<T>;
#[cfg(feature = "objc")]
pub type Rar<T> = ReturnedAutoReleased<T>;
#[cfg(target_arch = "aarch64")]
#[cfg(feature = "objc")]
#[inline]
pub fn rar_retain_option<T: objc::Obj>(id: Option<Rar<T>>) -> Option<R<T>> {
use std::arch::asm;
unsafe {
asm!("mov x29, x29");
std::mem::transmute(objc::objc_retainAutoreleasedReturnValue(
std::mem::transmute(id),
))
}
}
#[doc(alias = "objc_claimAutoreleasedReturnValue")]
#[cfg(target_arch = "aarch64")]
#[cfg(feature = "objc")]
#[inline]
pub fn rar_claim_value<T: objc::Obj>() -> Option<R<T>> {
unsafe { std::mem::transmute(objc::objc_claimAutoreleasedReturnValue()) }
}
#[cfg(target_arch = "x86_64")]
#[cfg(feature = "objc")]
#[inline]
pub fn rar_retain_option<T: objc::Obj>(id: Option<Rar<T>>) -> Option<R<T>> {
unsafe { std::mem::transmute(objc::objc_retain(std::mem::transmute(id))) }
}
#[cfg(feature = "objc")]
#[cfg(target_arch = "aarch64")]
#[inline]
pub fn rar_retain<T: objc::Obj>(id: Rar<T>) -> R<T> {
use std::arch::asm;
unsafe {
asm!("mov x29, x29");
std::mem::transmute(objc::objc_retainAutoreleasedReturnValue(
std::mem::transmute(id),
))
}
}
#[cfg(feature = "objc")]
#[cfg(target_arch = "x86_64")]
#[inline]
pub fn rar_retain<T: objc::Obj>(id: Rar<T>) -> R<T> {
unsafe { std::mem::transmute(objc::objc_retain(std::mem::transmute(id))) }
}