#![expect(
clippy::type_repetition_in_bounds,
reason = "trait-impl `where` clauses are kept uniform across all forwarding impls"
)]
use core::marker::PhantomData;
use core::mem::{MaybeUninit, forget, needs_drop};
use core::ptr::{NonNull, addr_eq, slice_from_raw_parts_mut};
use allocator_api2::alloc::{Allocator, Global};
use crate::internal::drop_list::{drop_shim_one, drop_shim_slice};
use crate::internal::in_chunk::InSharedChunk;
use crate::internal::shared_chunk::SharedChunk;
use crate::internal::sync::Ordering;
use crate::vec::Vec;
pub struct Arc<T: ?Sized, A: Allocator + Clone = Global> {
ptr: InSharedChunk<T, A>,
_phantom: PhantomData<(*const T, A)>,
}
impl<T: ?Sized, A: Allocator + Clone> Arc<T, A> {
#[inline]
pub(crate) unsafe fn from_value_ptr(ptr: NonNull<T>) -> Self {
unsafe { Self::from_in_chunk(InSharedChunk::new(ptr)) }
}
#[inline]
pub(crate) const unsafe fn from_in_chunk(ptr: InSharedChunk<T, A>) -> Self {
Self {
ptr,
_phantom: PhantomData,
}
}
#[inline]
pub(crate) fn from_owned_in_chunk(owned: crate::internal::owned_in_chunk::OwnedInSharedChunk<T, A>) -> Self {
Self {
ptr: owned.into_in_chunk(),
_phantom: PhantomData,
}
}
#[inline]
fn chunk(&self) -> &SharedChunk<A> {
unsafe { self.ptr.chunk_ptr().as_ref() }
}
#[inline]
#[must_use]
pub const fn as_ptr(&self) -> *const T {
self.ptr.as_ptr()
}
#[inline]
#[must_use]
pub fn ptr_eq(a: &Self, b: &Self) -> bool {
addr_eq(a.ptr.as_ptr(), b.ptr.as_ptr())
}
#[must_use]
#[inline]
pub fn into_pin(this: Self) -> core::pin::Pin<Self> {
unsafe { core::pin::Pin::new_unchecked(this) }
}
}
impl<T: ?Sized, A: Allocator + Clone> From<Arc<T, A>> for core::pin::Pin<Arc<T, A>> {
#[inline]
fn from(arc: Arc<T, A>) -> Self {
Arc::into_pin(arc)
}
}
impl<T, A: Allocator + Clone> Arc<MaybeUninit<T>, A> {
#[inline]
#[must_use]
pub unsafe fn assume_init(self) -> Arc<T, A> {
let ptr = self.ptr.as_non_null().cast::<T>();
if needs_drop::<T>() {
let chunk = self.chunk();
let data_addr = unsafe { SharedChunk::<A>::data_ptr(NonNull::from(chunk)) }.as_ptr() as usize;
let value_offset = self.ptr.as_ptr() as *const u8 as usize - data_addr;
let entry = chunk
.drop_entries_acquire()
.iter()
.find(|e| e.value_offset as usize == value_offset)
.expect(
"Arc::<MaybeUninit<T>>::assume_init: no drop entry reserved for this allocation. \
Use `Arena::alloc_uninit_arc::<T>()` / `alloc_zeroed_arc`; \
`Arena::alloc_arc(MaybeUninit::new(...))` does not reserve an entry and would silently leak `T::drop`.",
);
entry.store_drop_fn(drop_shim_one::<T>, Ordering::Release);
}
forget(self);
unsafe { Arc::from_value_ptr(ptr) }
}
#[must_use]
#[inline]
pub unsafe fn assume_init_pin(this: core::pin::Pin<Self>) -> core::pin::Pin<Arc<T, A>>
where
A: 'static,
{
unsafe {
let inner = core::pin::Pin::into_inner_unchecked(this);
core::pin::Pin::new_unchecked(inner.assume_init())
}
}
}
impl<T, A: Allocator + Clone> Arc<[MaybeUninit<T>], A> {
#[inline]
#[must_use]
pub unsafe fn assume_init(self) -> Arc<[T], A> {
let old_ptr = self.ptr.as_non_null();
let len = old_ptr.len();
if needs_drop::<T>() {
let chunk = self.chunk();
let data_addr = unsafe { SharedChunk::<A>::data_ptr(NonNull::from(chunk)) }.as_ptr() as usize;
let value_offset = old_ptr.as_ptr() as *const u8 as usize - data_addr;
let entry = chunk
.drop_entries_acquire()
.iter()
.find(|e| e.value_offset as usize == value_offset)
.expect(
"Arc::<[MaybeUninit<T>]>::assume_init: no drop entry reserved for this allocation. \
Use `Arena::alloc_uninit_slice_arc::<T>()` / `alloc_zeroed_slice_arc`; \
`alloc_slice_*_arc` of `MaybeUninit<T>` does not reserve an entry and would silently leak.",
);
entry.store_drop_fn(drop_shim_slice::<T>, Ordering::Release);
}
forget(self);
let data = old_ptr.as_ptr().cast::<T>();
let fat = slice_from_raw_parts_mut(data, len);
unsafe { Arc::from_value_ptr(NonNull::new_unchecked(fat)) }
}
#[must_use]
#[inline]
pub unsafe fn assume_init_pin_slice(this: core::pin::Pin<Self>) -> core::pin::Pin<Arc<[T], A>>
where
A: 'static,
{
unsafe {
let inner = core::pin::Pin::into_inner_unchecked(this);
core::pin::Pin::new_unchecked(inner.assume_init())
}
}
}
impl<T: ?Sized, A: Allocator + Clone> Clone for Arc<T, A> {
#[inline]
fn clone(&self) -> Self {
self.chunk().inc_ref();
Self {
ptr: self.ptr,
_phantom: PhantomData,
}
}
}
impl<T: ?Sized, A: Allocator + Clone> Drop for Arc<T, A> {
#[inline]
fn drop(&mut self) {
let chunk = self.ptr.chunk_ptr();
unsafe { SharedChunk::dec_ref(chunk) };
}
}
crate::smart_ptr_macros::impl_smart_ptr_forwarding_traits!(Arc);
unsafe impl<T: ?Sized + Sync + Send, A: Allocator + Clone + Send + Sync> Send for Arc<T, A> {}
unsafe impl<T: ?Sized + Sync + Send, A: Allocator + Clone + Send + Sync> Sync for Arc<T, A> {}
impl<'a, T, A: Allocator + Clone> From<Vec<'a, T, A>> for Arc<[T], A>
where
T: Send + Sync,
A: Send + Sync,
{
#[inline]
fn from(v: Vec<'a, T, A>) -> Self {
v.into_arena_arc()
}
}