use core::{
mem::ManuallyDrop,
ops::Deref,
ptr::NonNull,
sync::atomic::{AtomicUsize, Ordering},
};
use alloc::boxed::Box;
struct ArcData<T> {
ref_count: AtomicUsize,
data: T,
}
pub struct Arky<T> {
ptr: NonNull<ArcData<T>>,
}
unsafe impl<T: Send + Sync> Send for Arky<T> {}
unsafe impl<T: Send + Sync> Sync for Arky<T> {}
impl<T> Arky<T> {
pub fn new(data: T) -> Arky<T> {
Arky {
ptr: NonNull::from(Box::leak(Box::new(ArcData {
ref_count: AtomicUsize::new(1),
data,
}))),
}
}
fn data(&self) -> &ArcData<T> {
unsafe { self.ptr.as_ref() }
}
}
impl<T> Deref for Arky<T> {
type Target = T;
fn deref(&self) -> &T {
&self.data().data
}
}
impl<T> Clone for Arky<T> {
fn clone(&self) -> Self {
let current = self.data().ref_count.load(Ordering::Acquire);
self.data().ref_count.store(current + 1, Ordering::Release);
Arky { ptr: self.ptr }
}
}
impl<T> Drop for Arky<T> {
fn drop(&mut self) {
let current = self.data().ref_count.load(Ordering::Acquire);
let _ = &self.data().ref_count.store(current - 1, Ordering::Release);
if current == 1 {
unsafe {
drop(Box::from_raw(self.ptr.as_ptr()));
}
}
}
}
impl<T: core::fmt::Debug> core::fmt::Debug for Arky<T> {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
self.data().data.fmt(f)
}
}
impl<T: PartialEq> PartialEq for Arky<T> {
fn eq(&self, other: &Self) -> bool {
self.data().data == other.data().data
}
}
impl<T: Eq> Eq for Arky<T> {
}