use super::ObjectType;
use std::{
fmt,
hash::{Hash, Hasher},
mem::{self, ManuallyDrop},
ops::Deref,
ptr::NonNull,
};
#[repr(transparent)]
pub struct Arc<T: ObjectType> {
obj: NonNull<T>,
}
impl<T: ObjectType> Clone for Arc<T> {
#[inline]
fn clone(&self) -> Self {
Arc::retain(self)
}
}
impl<T: ObjectType> Drop for Arc<T> {
#[inline]
fn drop(&mut self) {
unsafe { T::release(self.obj.cast()) };
}
}
impl<T: ObjectType> Deref for Arc<T> {
type Target = T;
#[inline]
fn deref(&self) -> &Self::Target {
unsafe { self.obj.as_ref() }
}
}
impl<T: ObjectType> AsRef<T> for Arc<T> {
#[inline]
fn as_ref(&self) -> &T {
self
}
}
unsafe impl<T: ObjectType + Send + Sync> Send for Arc<T> {}
unsafe impl<T: ObjectType + Send + Sync> Sync for Arc<T> {}
impl<'a, T: ObjectType + 'a> Default for Arc<T>
where
&'a T: Default,
{
#[inline]
fn default() -> Self {
Arc::retain(<&T>::default())
}
}
impl<T: ObjectType + fmt::Display> fmt::Display for Arc<T> {
#[inline]
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
(**self).fmt(f)
}
}
impl<T: ObjectType + fmt::Debug> fmt::Debug for Arc<T> {
#[inline]
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
(**self).fmt(f)
}
}
impl<T: ObjectType> fmt::Pointer for Arc<T> {
#[inline]
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
self.obj.fmt(f)
}
}
impl<T: ObjectType + Hash> Hash for Arc<T> {
#[inline]
fn hash<H: Hasher>(&self, state: &mut H) {
(**self).hash(state);
}
}
impl<T: ObjectType> Arc<T> {
#[inline]
#[must_use = "The retained object is immediately released if unused"]
pub fn retain(obj: &T) -> Self {
ObjectType::retain(obj)
}
#[inline]
pub unsafe fn from_raw(obj: *const T) -> Self {
Self {
obj: NonNull::new_unchecked(obj as *mut T),
}
}
#[inline]
pub unsafe fn retain_raw(obj: *const T) -> Self {
Self::retain(&ManuallyDrop::new(Self::from_raw(obj)))
}
#[inline]
pub fn into_raw(this: Self) -> *const T {
let obj = this.obj;
mem::forget(this);
obj.as_ptr()
}
#[inline]
pub unsafe fn cast_unchecked<U: ObjectType>(this: Self) -> Arc<U> {
Arc::from_raw(Self::into_raw(this).cast())
}
}