#![expect(
clippy::type_repetition_in_bounds,
clippy::cast_sign_loss,
reason = "trait-impl `where` clauses are kept uniform across all forwarding impls; numeric casts are bounded by upstream `usize` checks documented at call sites"
)]
use core::borrow::{Borrow, BorrowMut};
use core::cmp::Ordering;
use core::fmt::{self, Debug, Display, Formatter, Pointer};
use core::hash::{Hash, Hasher};
use core::iter::FusedIterator;
use core::marker::PhantomData;
use core::mem::{MaybeUninit, forget, needs_drop};
use core::ops::{Deref, DerefMut};
use core::pin::Pin;
use core::ptr::{NonNull, drop_in_place, slice_from_raw_parts_mut};
use core::sync::atomic::Ordering as AtomicOrdering;
use allocator_api2::alloc::{Allocator, Global};
use crate::internal::drop_list::{drop_shim_one, drop_shim_slice};
use crate::internal::in_chunk::InLocalChunk;
use crate::internal::local_chunk::LocalChunk;
use crate::rc::Rc;
pub struct Box<T: ?Sized, A: Allocator + Clone = Global> {
ptr: InLocalChunk<T, A>,
_phantom: PhantomData<(*const T, A)>,
}
impl<T, A: Allocator + Clone> Box<T, A> {
#[must_use]
#[inline]
pub(crate) const unsafe fn from_raw(ptr: NonNull<T>) -> Self {
unsafe { Self::from_in_chunk(InLocalChunk::new(ptr)) }
}
#[must_use]
#[inline]
pub(crate) const unsafe fn from_in_chunk(ptr: InLocalChunk<T, A>) -> Self {
Self {
ptr,
_phantom: PhantomData,
}
}
#[must_use]
#[inline]
pub(crate) fn from_owned_in_chunk(owned: crate::internal::owned_in_chunk::OwnedInLocalChunk<T, A>) -> Self {
Self {
ptr: owned.into_in_chunk(),
_phantom: PhantomData,
}
}
#[must_use]
#[inline]
pub fn into_rc(self) -> Rc<T, A> {
let in_chunk = self.ptr;
let value_ptr = in_chunk.as_non_null();
if needs_drop::<T>() {
retarget_box_drop_entry::<A>(self.chunk(), value_ptr.cast::<u8>(), drop_shim_one::<T>);
}
forget(self);
unsafe { Rc::from_in_chunk(in_chunk) }
}
}
impl<T: ?Sized, A: Allocator + Clone> Box<T, A> {
#[must_use]
#[inline]
pub(crate) const unsafe fn from_raw_unsized(ptr: NonNull<T>) -> Self {
unsafe { Self::from_in_chunk_unsized(InLocalChunk::new(ptr)) }
}
#[must_use]
#[inline]
pub(crate) const unsafe fn from_in_chunk_unsized(ptr: InLocalChunk<T, A>) -> Self {
Self {
ptr,
_phantom: PhantomData,
}
}
#[must_use]
#[inline]
pub(crate) fn from_owned_in_chunk_unsized(owned: crate::internal::owned_in_chunk::OwnedInLocalChunk<T, A>) -> Self {
Self {
ptr: owned.into_in_chunk(),
_phantom: PhantomData,
}
}
#[inline]
fn chunk(&self) -> &LocalChunk<A> {
unsafe { self.ptr.chunk_ptr().as_ref() }
}
#[must_use]
#[inline]
pub const fn as_ptr(&self) -> *const T {
self.ptr.as_ptr()
}
#[expect(
clippy::needless_pass_by_ref_mut,
reason = "associated-fn convention (like alloc::rc::Rc::as_ptr); &mut self conveys exclusive access"
)]
#[must_use]
#[inline]
pub const fn as_mut_ptr(this: &mut Self) -> *mut T {
this.ptr.as_ptr()
}
#[must_use]
#[inline]
pub fn into_pin(boxed: Self) -> Pin<Self> {
unsafe { Pin::new_unchecked(boxed) }
}
}
impl<T: ?Sized, A: Allocator + Clone> From<Box<T, A>> for Pin<Box<T, A>> {
#[inline]
fn from(boxed: Box<T, A>) -> Self {
Box::into_pin(boxed)
}
}
impl<T, A: Allocator + Clone> Box<[T], A> {
#[must_use]
#[inline]
#[cfg_attr(test, mutants::skip)] pub fn into_rc(self) -> Rc<[T], A> {
let in_chunk = self.ptr;
let value_ptr = in_chunk.as_non_null();
let len = value_ptr.len();
if needs_drop::<T>() && len > 0 {
retarget_box_drop_entry::<A>(self.chunk(), value_ptr.cast::<u8>(), drop_shim_slice::<T>);
}
forget(self);
unsafe { Rc::from_in_chunk(in_chunk) }
}
}
impl<T, A: Allocator + Clone> Box<MaybeUninit<T>, A> {
#[must_use]
#[inline]
pub unsafe fn assume_init(self) -> Box<T, A> {
let ptr = self.ptr.as_non_null();
forget(self);
unsafe { Box::from_raw(ptr.cast::<T>()) }
}
#[must_use]
#[inline]
pub unsafe fn assume_init_pin(this: Pin<Self>) -> Pin<Box<T, A>>
where
A: 'static,
{
unsafe {
let inner = Pin::into_inner_unchecked(this);
Pin::new_unchecked(inner.assume_init())
}
}
}
impl<T, A: Allocator + Clone> Box<[MaybeUninit<T>], A> {
#[must_use]
#[inline]
pub unsafe fn assume_init(self) -> Box<[T], A> {
let ptr = self.ptr.as_non_null();
let len = ptr.len();
forget(self);
let data = ptr.as_ptr().cast::<T>();
let fat = slice_from_raw_parts_mut(data, len);
unsafe { Box::from_raw_unsized(NonNull::new_unchecked(fat)) }
}
#[must_use]
#[inline]
pub unsafe fn assume_init_pin_slice(this: Pin<Self>) -> Pin<Box<[T], A>>
where
A: 'static,
{
unsafe {
let inner = Pin::into_inner_unchecked(this);
Pin::new_unchecked(inner.assume_init())
}
}
}
impl<T: ?Sized, A: Allocator + Clone> Drop for Box<T, A> {
#[inline]
#[expect(
clippy::items_after_statements,
reason = "the release-guard helper struct is local to the slow-path arm and reads better inline"
)]
fn drop(&mut self) {
let chunk = self.ptr.chunk_ptr();
struct ReleaseGuard<A: Allocator + Clone>(NonNull<LocalChunk<A>>);
impl<A: Allocator + Clone> Drop for ReleaseGuard<A> {
fn drop(&mut self) {
unsafe { LocalChunk::dec_ref(self.0) };
}
}
let _guard = ReleaseGuard::<A>(chunk);
unsafe { drop_in_place(self.ptr.as_ptr()) };
}
}
impl<T: ?Sized, A: Allocator + Clone> DerefMut for Box<T, A> {
#[inline]
fn deref_mut(&mut self) -> &mut T {
unsafe { self.ptr.as_mut() }
}
}
impl<T: ?Sized, A: Allocator + Clone> AsMut<T> for Box<T, A> {
#[inline]
fn as_mut(&mut self) -> &mut T {
self
}
}
impl<T: ?Sized, A: Allocator + Clone> BorrowMut<T> for Box<T, A> {
#[inline]
fn borrow_mut(&mut self) -> &mut T {
self
}
}
impl<T, A: Allocator + Clone> From<Box<T, A>> for Rc<T, A> {
#[inline]
fn from(b: Box<T, A>) -> Self {
b.into_rc()
}
}
impl<T, A: Allocator + Clone> From<Box<[T], A>> for Rc<[T], A> {
#[inline]
fn from(b: Box<[T], A>) -> Self {
b.into_rc()
}
}
impl<T: ?Sized, A: Allocator + Clone> Deref for Box<T, A> {
type Target = T;
#[inline]
fn deref(&self) -> &T {
unsafe { self.ptr.as_ref() }
}
}
impl<T: ?Sized, A: Allocator + Clone> Debug for Box<T, A>
where
T: Debug,
{
#[inline]
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
Debug::fmt(&**self, f)
}
}
impl<T: ?Sized, A: Allocator + Clone> Display for Box<T, A>
where
T: Display,
{
#[inline]
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
Display::fmt(&**self, f)
}
}
impl<T: ?Sized, A: Allocator + Clone> PartialEq for Box<T, A>
where
T: PartialEq,
{
#[inline]
fn eq(&self, other: &Self) -> bool {
**self == **other
}
}
impl<T: ?Sized, A: Allocator + Clone> Eq for Box<T, A> where T: Eq {}
impl<T: ?Sized, A: Allocator + Clone> PartialOrd for Box<T, A>
where
T: PartialOrd,
{
#[inline]
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
(**self).partial_cmp(&**other)
}
}
impl<T: ?Sized, A: Allocator + Clone> Ord for Box<T, A>
where
T: Ord,
{
#[inline]
fn cmp(&self, other: &Self) -> Ordering {
(**self).cmp(&**other)
}
}
impl<T: ?Sized, A: Allocator + Clone> Hash for Box<T, A>
where
T: Hash,
{
#[inline]
fn hash<H: Hasher>(&self, state: &mut H) {
(**self).hash(state);
}
}
impl<T: ?Sized, A: Allocator + Clone> AsRef<T> for Box<T, A> {
#[inline]
fn as_ref(&self) -> &T {
self
}
}
impl<T: ?Sized, A: Allocator + Clone> Borrow<T> for Box<T, A> {
#[inline]
fn borrow(&self) -> &T {
self
}
}
impl<T: ?Sized, A: Allocator + Clone> Pointer for Box<T, A> {
#[inline]
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
Pointer::fmt(&self.ptr.as_ptr(), f)
}
}
impl<I: Iterator + ?Sized, A: Allocator + Clone> Iterator for Box<I, A> {
type Item = I::Item;
#[inline]
fn next(&mut self) -> Option<Self::Item> {
(**self).next()
}
#[inline]
fn size_hint(&self) -> (usize, Option<usize>) {
(**self).size_hint()
}
#[inline]
fn nth(&mut self, n: usize) -> Option<Self::Item> {
(**self).nth(n)
}
}
impl<I: DoubleEndedIterator + ?Sized, A: Allocator + Clone> DoubleEndedIterator for Box<I, A> {
#[inline]
fn next_back(&mut self) -> Option<Self::Item> {
(**self).next_back()
}
#[inline]
fn nth_back(&mut self, n: usize) -> Option<Self::Item> {
(**self).nth_back(n)
}
}
impl<I: ExactSizeIterator + ?Sized, A: Allocator + Clone> ExactSizeIterator for Box<I, A> {
#[inline]
fn len(&self) -> usize {
(**self).len()
}
}
impl<I: FusedIterator + ?Sized, A: Allocator + Clone> FusedIterator for Box<I, A> {}
impl<T: ?Sized, A: Allocator + Clone> Unpin for Box<T, A> {}
fn retarget_box_drop_entry<A: Allocator + Clone>(chunk: &LocalChunk<A>, value_ptr: NonNull<u8>, drop_fn: unsafe fn(*mut u8, usize)) {
let data = unsafe { LocalChunk::<A>::data_ptr(NonNull::from(chunk)) };
let value_offset = unsafe { value_ptr.as_ptr().offset_from(data.as_ptr()) } as usize;
if let Some(entry) = chunk.drop_entries().iter().find(|e| e.value_offset as usize == value_offset) {
entry.store_drop_fn(drop_fn, AtomicOrdering::Relaxed);
return;
}
#[expect(
clippy::panic,
reason = "intentional: surface the contract violation rather than leak T::drop silently"
)]
{
panic!(
"Box::into_rc: no drop entry reserved for this allocation. \
Use `Arena::alloc_uninit_box::<T>()` so the entry is installed eagerly; \
`alloc_box(MaybeUninit::new(...))` does not reserve one."
);
}
}