#![allow(
clippy::type_repetition_in_bounds,
reason = "trait-impl `where` clauses are kept uniform across all forwarding impls"
)]
use core::marker::PhantomData;
use core::mem::{self, MaybeUninit};
use core::pin::Pin;
use core::ptr::{self, NonNull};
use allocator_api2::alloc::{Allocator, Global};
use ptr_meta::Pointee;
use crate::internal::chunk::Chunk;
use crate::internal::chunk_ref::ChunkRef;
use crate::internal::drop_entry::{self, DropFn};
use crate::internal::shared_chunk::SharedChunk;
use crate::internal::thin_dst;
use crate::thin_smart_ptr_common::impl_thin_smart_ptr_common;
use crate::vec::Vec;
pub struct Arc<T: ?Sized + Pointee, A: Allocator + Clone = Global> {
ptr: NonNull<u8>,
_phantom: PhantomData<(*const T, A)>,
}
impl<T: ?Sized + Pointee, A: Allocator + Clone> Arc<T, A> {
#[inline]
pub(crate) unsafe fn from_raw(thin: NonNull<u8>) -> Self {
Self {
ptr: thin,
_phantom: PhantomData,
}
}
#[inline]
pub(crate) fn thin_ptr(&self) -> NonNull<u8> {
self.ptr
}
#[inline]
#[must_use]
pub fn ptr_eq(a: &Self, b: &Self) -> bool {
ptr::addr_eq(a.ptr.as_ptr(), b.ptr.as_ptr())
}
}
impl_thin_smart_ptr_common!(Arc);
impl<T, A: Allocator + Clone> Arc<MaybeUninit<T>, A> {
#[inline]
#[must_use]
pub unsafe fn assume_init(self) -> Arc<T, A> {
if const { mem::needs_drop::<T>() } {
unsafe {
commit_uninit_drop_entry::<A>(self.ptr, 1, drop_entry::drop_shim::<T>, false);
}
}
let thin = self.ptr;
mem::forget(self);
unsafe { Arc::from_raw(thin) }
}
#[must_use]
#[inline]
pub unsafe fn assume_init_pin(this: Pin<Self>) -> Pin<Arc<T, A>>
where
A: 'static,
{
unsafe {
let inner: Self = Pin::into_inner_unchecked(this);
Arc::into_pin(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 len: usize = unsafe { thin_dst::read_metadata::<[T]>(self.ptr) };
if const { mem::needs_drop::<T>() } {
unsafe {
commit_uninit_drop_entry::<A>(self.ptr, len, drop_entry::drop_shim::<T>, true);
}
}
let thin = self.ptr;
mem::forget(self);
unsafe { Arc::from_raw(thin) }
}
#[must_use]
#[inline]
pub unsafe fn assume_init_pin_slice(this: Pin<Self>) -> Pin<Arc<[T], A>>
where
A: 'static,
{
unsafe {
let inner: Self = Pin::into_inner_unchecked(this);
Arc::into_pin(inner.assume_init())
}
}
}
#[inline]
unsafe fn commit_uninit_drop_entry<A: Allocator + Clone>(value: NonNull<u8>, len: usize, drop_fn: DropFn, is_slice: bool) {
let header = SharedChunk::<A>::header_from_value_ptr(value);
let chunk = unsafe { NonNull::new_unchecked(SharedChunk::<A>::header_to_fat(header.as_ptr())) };
let chunk_ref = unsafe { chunk.as_ref() };
let payload = unsafe { SharedChunk::<A>::payload_ptr(chunk) }.as_ptr();
let payload_len = chunk_ref.capacity();
let value_offset = (value.as_ptr() as usize) - (payload as usize);
let count = chunk_ref.drop_entry_count_acquire();
let committed = unsafe { drop_entry::commit_placeholder_drop_fn(payload, payload_len, count, value_offset, len, drop_fn) };
assert!(
committed,
"{}",
if is_slice {
"Arc::<[MaybeUninit<T>]>::assume_init: no drop entry reserved for this allocation. \
Use `Arena::alloc_uninit_slice_arc::<T>()` / `alloc_zeroed_slice_arc`; allocating \
a `MaybeUninit<T>` slice via the ordinary slice-Arc helpers does not reserve one \
and would silently leak each `T::drop`."
} else {
"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`."
}
);
}
impl<T: ?Sized + Pointee, A: Allocator + Clone> Clone for Arc<T, A> {
#[inline]
fn clone(&self) -> Self {
let chunk_ref = unsafe { ChunkRef::<A>::clone_from_value_ptr(self.ptr) };
let _ = chunk_ref.forget();
Self {
ptr: self.ptr,
_phantom: PhantomData,
}
}
}
impl<T: ?Sized + Pointee, A: Allocator + Clone> Drop for Arc<T, A> {
#[inline]
fn drop(&mut self) {
unsafe {
let _ref: ChunkRef<A> = ChunkRef::from_value_ptr(self.ptr);
}
}
}
unsafe impl<T: ?Sized + Pointee + Sync + Send, A: Allocator + Clone + Send + Sync> Send for Arc<T, A> {}
unsafe impl<T: ?Sized + Pointee + 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.freeze_into_arc()
}
}