use alloc::boxed::Box;
use core::{
fmt::Debug,
mem::MaybeUninit,
ops::Deref,
sync::atomic::{AtomicUsize, Ordering},
};
#[derive(Debug)]
#[repr(C)]
struct ArcInner<T> {
count: AtomicUsize,
data: T,
}
pub(super) struct Arc<T>(*mut ArcInner<T>);
unsafe impl<T: Send + Sync> Send for Arc<T> {}
unsafe impl<T: Send + Sync> Sync for Arc<T> {}
impl<T> Deref for Arc<T> {
type Target = T;
#[inline]
fn deref(&self) -> &Self::Target {
&self.inner().data
}
}
impl<T: Debug> Debug for Arc<T> {
#[inline]
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
T::fmt(self, f)
}
}
impl<T> Clone for Arc<T> {
#[inline]
fn clone(&self) -> Self {
const MAX_REFCOUNT: usize = (isize::MAX) as usize;
let old_size = self.inner().count.fetch_add(1, Ordering::Relaxed);
assert!(
old_size <= MAX_REFCOUNT,
"Suspiciously many `Arc`s pointing to the same location"
);
Self(self.0)
}
}
impl<T> Arc<MaybeUninit<T>> {
#[inline]
pub(super) fn uninit() -> Self {
let inner = Box::new(ArcInner {
count: AtomicUsize::new(1),
data: MaybeUninit::uninit(),
});
let ptr = Box::into_raw(inner);
Self(ptr)
}
#[inline]
pub(super) unsafe fn assume_init(mut self) -> Arc<T> {
let uptr = core::mem::replace(&mut self.0, core::ptr::null_mut());
drop(self);
let ptr = uptr.cast::<ArcInner<T>>();
Arc(ptr)
}
}
impl<T> Arc<T> {
#[inline]
fn ptr(&self) -> *const ArcInner<T> {
self.0.cast_const()
}
#[inline]
fn ptr_mut(&mut self) -> *mut ArcInner<T> {
self.0
}
#[inline]
fn inner(&self) -> &ArcInner<T> {
unsafe { &*self.ptr() }
}
#[inline]
pub(super) fn count(this: &Self) -> usize {
this.inner().count.load(Ordering::Acquire)
}
#[inline]
pub(super) fn is_unique(&self) -> bool {
Self::count(self) == 1
}
#[inline]
pub(super) fn get_mut(&mut self) -> Option<&mut T> {
self.is_unique().then(|| {
unsafe { self.get_mut_unchecked() }
})
}
#[inline]
pub(super) unsafe fn get_mut_unchecked(&mut self) -> &mut T {
&mut unsafe { &mut *self.ptr_mut() }.data
}
#[inline]
pub(super) fn try_move_out<O>(mut self, op: impl FnOnce(*mut T) -> O) -> Option<O> {
let ptr = core::mem::replace(&mut self.0, core::ptr::null_mut());
drop(self);
{
let count = &unsafe { &*ptr }.count;
if count.fetch_sub(1, Ordering::Release) != 1 {
return None;
}
}
let inner = unsafe { &mut *ptr };
let data_ptr = core::ptr::from_mut(&mut inner.data);
#[expect(dropping_references, reason = "Ensuring the reference is not live")]
drop(inner);
let res = op(data_ptr);
let uptr = ptr.cast::<ArcInner<MaybeUninit<T>>>();
drop(unsafe { Box::from_raw(uptr) });
Some(res)
}
}
impl<T> Drop for Arc<T> {
#[inline]
fn drop(&mut self) {
if self.0.is_null() {
return;
}
if self.inner().count.fetch_sub(1, Ordering::Release) != 1 {
return;
}
self.inner().count.load(Ordering::Acquire);
drop(unsafe { Box::from_raw(self.ptr_mut()) });
}
}