use core::{
any::Any,
borrow::{Borrow, BorrowMut},
cmp::Ordering,
fmt::{Debug, Display},
hash::{Hash, Hasher},
marker::PhantomData,
mem::{self, ManuallyDrop, MaybeUninit},
ops::{self, Deref, DerefMut, Index, IndexMut, Range, RangeBounds},
ptr::{self, NonNull},
slice, str,
};
#[cfg(feature = "nightly-fn-traits")]
use core::{alloc::Layout, marker::Tuple};
#[cfg(feature = "std")]
use alloc_crate::{string::String, vec::Vec};
#[cfg(feature = "alloc")]
#[expect(unused_imports)]
use alloc_crate::boxed::Box;
use crate::{
FromUtf8Error, NoDrop, SizedTypeProperties,
alloc::BoxLike,
owned_slice::{self, OwnedSlice, TakeOwnedSlice},
owned_str,
polyfill::{self, non_null, pointer, transmute_mut},
set_len_on_drop_by_ptr::SetLenOnDropByPtr,
traits::BumpAllocatorTypedScope,
};
mod raw;
mod slice_initializer;
pub(crate) use raw::RawBumpBox;
pub(crate) use slice_initializer::BumpBoxSliceInitializer;
#[repr(transparent)]
pub struct BumpBox<'a, T: ?Sized> {
ptr: NonNull<T>,
marker: PhantomData<(&'a (), T)>,
}
#[cfg_attr(feature = "nightly-coerce-unsized", doc = "```")]
#[cfg_attr(not(feature = "nightly-coerce-unsized"), doc = "```ignore")]
#[macro_export]
macro_rules! unsize_bump_box {
($boxed:expr) => {{
let (ptr, lt) = $crate::private::bump_box_into_raw_with_lifetime($boxed);
let ptr: $crate::private::core::ptr::NonNull<_> = ptr;
unsafe { $crate::private::bump_box_from_raw_with_lifetime(ptr, lt) }
}};
}
unsafe impl<T: ?Sized + Send> Send for BumpBox<'_, T> {}
unsafe impl<T: ?Sized + Sync> Sync for BumpBox<'_, T> {}
impl<T> BumpBox<'_, T> {
#[must_use]
#[inline(always)]
pub(crate) fn zst(value: T) -> Self {
assert!(T::IS_ZST);
mem::forget(value);
Self {
ptr: NonNull::dangling(),
marker: PhantomData,
}
}
#[must_use]
#[inline(always)]
pub(crate) fn zst_uninit() -> BumpBox<'static, MaybeUninit<T>> {
assert!(T::IS_ZST);
BumpBox {
ptr: NonNull::dangling(),
marker: PhantomData,
}
}
}
impl<'a, T: ?Sized + NoDrop> BumpBox<'a, T> {
#[must_use]
#[inline(always)]
pub fn into_ref(self) -> &'a T {
self.into_mut()
}
#[must_use]
#[inline(always)]
pub fn into_mut(self) -> &'a mut T {
Self::leak(self)
}
}
impl<'a, T: ?Sized> BumpBox<'a, T> {
#[must_use]
#[inline(always)]
pub(crate) const fn ptr(&self) -> NonNull<T> {
self.ptr
}
#[must_use]
#[inline(always)]
pub(crate) unsafe fn mut_ptr(&mut self) -> &mut NonNull<T> {
&mut self.ptr
}
#[cfg_attr(feature = "allocator-api2-04", doc = "```")]
#[cfg_attr(not(feature = "allocator-api2-04"), doc = "```ignore")]
#[must_use]
#[inline(always)]
pub fn into_box<A, B>(self, allocator: A) -> B
where
A: BumpAllocatorTypedScope<'a>,
B: BoxLike<T = T, A = A>,
{
let ptr = BumpBox::into_raw(self).as_ptr();
unsafe { B::from_raw_in(ptr, allocator) }
}
#[inline(always)]
#[expect(clippy::must_use_candidate)]
pub fn leak(boxed: Self) -> &'a mut T {
unsafe { BumpBox::into_raw(boxed).as_mut() }
}
#[inline]
#[must_use]
pub const fn as_raw(b: &Self) -> NonNull<T> {
b.ptr
}
#[inline(always)]
#[must_use = "use `leak` if you don't make use of the pointer"]
pub fn into_raw(self) -> NonNull<T> {
ManuallyDrop::new(self).ptr
}
#[must_use]
#[inline(always)]
pub unsafe fn from_raw(ptr: NonNull<T>) -> Self {
Self {
ptr,
marker: PhantomData,
}
}
}
impl<'a, T> BumpBox<'a, T> {
#[must_use]
#[inline(always)]
pub fn into_inner(self) -> T {
unsafe { self.into_raw().read() }
}
#[must_use]
#[inline(always)]
pub fn into_boxed_slice(self) -> BumpBox<'a, [T]> {
unsafe {
let ptr = self.into_raw();
let ptr = NonNull::slice_from_raw_parts(ptr, 1);
BumpBox::from_raw(ptr)
}
}
}
impl<'a> BumpBox<'a, str> {
pub const EMPTY_STR: Self = unsafe { BumpBox::from_utf8_unchecked(BumpBox::<[u8]>::EMPTY) };
pub const fn from_utf8(bytes: BumpBox<'a, [u8]>) -> Result<Self, FromUtf8Error<BumpBox<'a, [u8]>>> {
match str::from_utf8(bytes.as_slice()) {
Ok(_) => Ok(unsafe { mem::transmute(bytes) }),
Err(error) => Err(FromUtf8Error::new(error, bytes)),
}
}
#[must_use]
pub const unsafe fn from_utf8_unchecked(bytes: BumpBox<'a, [u8]>) -> Self {
debug_assert!(str::from_utf8(bytes.as_slice()).is_ok());
unsafe { mem::transmute(bytes) }
}
#[inline]
#[must_use]
pub fn into_boxed_bytes(self) -> BumpBox<'a, [u8]> {
BumpBox {
ptr: non_null::str_bytes(self.ptr),
marker: PhantomData,
}
}
#[must_use]
#[inline(always)]
pub unsafe fn as_mut_bytes(&mut self) -> &mut BumpBox<'a, [u8]> {
unsafe {
transmute_mut(self)
}
}
#[must_use]
#[inline(always)]
pub const fn len(&self) -> usize {
non_null::str_len(self.ptr)
}
#[must_use]
#[inline(always)]
pub const fn is_empty(&self) -> bool {
self.len() == 0
}
#[track_caller]
pub(crate) fn assert_char_boundary(&self, index: usize) {
#[cold]
#[track_caller]
#[inline(never)]
fn assert_failed() {
panic!("index is not on a char boundary")
}
if !self.is_char_boundary(index) {
assert_failed();
}
}
#[inline]
#[expect(clippy::return_self_not_must_use)]
pub fn split_off(&mut self, range: impl RangeBounds<usize>) -> Self {
let len = self.len();
let ops::Range { start, end } = polyfill::slice::range(range, ..len);
let ptr = non_null::as_non_null_ptr(non_null::str_bytes(self.ptr));
if end == len {
self.assert_char_boundary(start);
let lhs = NonNull::slice_from_raw_parts(ptr, start);
let rhs = NonNull::slice_from_raw_parts(unsafe { ptr.add(start) }, len - start);
self.ptr = non_null::str_from_utf8(lhs);
return unsafe { BumpBox::from_raw(non_null::str_from_utf8(rhs)) };
}
if start == 0 {
self.assert_char_boundary(end);
let lhs = NonNull::slice_from_raw_parts(ptr, end);
let rhs = NonNull::slice_from_raw_parts(unsafe { ptr.add(end) }, len - end);
self.ptr = non_null::str_from_utf8(rhs);
return unsafe { BumpBox::from_raw(non_null::str_from_utf8(lhs)) };
}
if start == end {
return BumpBox::EMPTY_STR;
}
self.assert_char_boundary(start);
self.assert_char_boundary(end);
let head_len = start;
let tail_len = len - end;
let range_len = end - start;
let remaining_len = len - range_len;
unsafe {
if head_len < tail_len {
self.as_mut_bytes().get_unchecked_mut(..end).rotate_right(range_len);
let lhs = NonNull::slice_from_raw_parts(ptr, range_len);
let rhs = NonNull::slice_from_raw_parts(ptr.add(range_len), remaining_len);
let lhs = non_null::str_from_utf8(lhs);
let rhs = non_null::str_from_utf8(rhs);
self.ptr = rhs;
BumpBox::from_raw(lhs)
} else {
self.as_mut_bytes().get_unchecked_mut(start..).rotate_left(range_len);
let lhs = NonNull::slice_from_raw_parts(ptr, remaining_len);
let rhs = NonNull::slice_from_raw_parts(ptr.add(remaining_len), range_len);
let lhs = non_null::str_from_utf8(lhs);
let rhs = non_null::str_from_utf8(rhs);
self.ptr = lhs;
BumpBox::from_raw(rhs)
}
}
}
#[inline]
pub fn pop(&mut self) -> Option<char> {
let ch = self.chars().next_back()?;
let new_len = self.len() - ch.len_utf8();
unsafe {
self.set_len(new_len);
}
Some(ch)
}
#[inline]
pub fn truncate(&mut self, new_len: usize) {
if new_len <= self.len() {
self.assert_char_boundary(new_len);
unsafe { self.as_mut_bytes().truncate(new_len) }
}
}
#[inline(always)]
pub fn clear(&mut self) {
unsafe {
self.set_len(0);
}
}
#[inline]
#[must_use]
pub fn as_ptr(&self) -> *const u8 {
self.ptr.as_ptr().cast()
}
#[inline]
pub fn as_mut_ptr(&mut self) -> *mut u8 {
self.ptr.as_ptr().cast()
}
#[must_use]
#[inline(always)]
pub const fn as_non_null(&self) -> NonNull<u8> {
self.ptr.cast()
}
#[inline(always)]
pub(crate) unsafe fn set_ptr(&mut self, new_ptr: NonNull<u8>) {
self.ptr = non_null::str_from_utf8(NonNull::slice_from_raw_parts(new_ptr, self.len()));
}
#[inline]
pub unsafe fn set_len(&mut self, new_len: usize) {
let ptr = self.ptr.cast::<u8>();
let bytes = NonNull::slice_from_raw_parts(ptr, new_len);
self.ptr = non_null::str_from_utf8(bytes);
}
#[inline]
pub fn remove(&mut self, idx: usize) -> char {
let Some(ch) = self[idx..].chars().next() else {
panic!("cannot remove a char from the end of a string");
};
let next = idx + ch.len_utf8();
let len = self.len();
unsafe {
ptr::copy(self.as_ptr().add(next), self.as_mut_ptr().add(idx), len - next);
self.set_len(len - (next - idx));
}
ch
}
#[inline]
pub fn retain<F>(&mut self, mut f: F)
where
F: FnMut(char) -> bool,
{
struct SetLenOnDrop<'b, 'a> {
s: &'b mut BumpBox<'a, str>,
idx: usize,
del_bytes: usize,
}
impl Drop for SetLenOnDrop<'_, '_> {
fn drop(&mut self) {
let new_len = self.idx - self.del_bytes;
debug_assert!(new_len <= self.s.len());
unsafe { self.s.set_len(new_len) };
}
}
let len = self.len();
let mut guard = SetLenOnDrop {
s: self,
idx: 0,
del_bytes: 0,
};
while guard.idx < len {
let ch =
unsafe { guard.s.get_unchecked(guard.idx..len).chars().next().unwrap_unchecked() };
let ch_len = ch.len_utf8();
if !f(ch) {
guard.del_bytes += ch_len;
} else if guard.del_bytes > 0 {
ch.encode_utf8(unsafe {
slice::from_raw_parts_mut(guard.s.as_mut_ptr().add(guard.idx - guard.del_bytes), ch.len_utf8())
});
}
guard.idx += ch_len;
}
drop(guard);
}
pub fn drain<R>(&mut self, range: R) -> owned_str::Drain<'_>
where
R: RangeBounds<usize>,
{
let Range { start, end } = polyfill::slice::range(range, ..self.len());
self.assert_char_boundary(start);
self.assert_char_boundary(end);
let self_ptr = unsafe { NonNull::new_unchecked(ptr::from_mut(self)) };
let chars_iter = unsafe { self.get_unchecked(start..end) }.chars();
owned_str::Drain {
start,
end,
iter: chars_iter,
string: self_ptr,
}
}
}
impl<'a, T: Sized> BumpBox<'a, MaybeUninit<T>> {
#[must_use]
#[inline(always)]
pub fn init(mut self, value: T) -> BumpBox<'a, T> {
self.as_mut().write(value);
unsafe { self.assume_init() }
}
#[must_use]
#[inline(always)]
pub unsafe fn assume_init(self) -> BumpBox<'a, T> {
unsafe {
let ptr = BumpBox::into_raw(self);
BumpBox::from_raw(ptr.cast())
}
}
}
impl<'a, T: Sized> BumpBox<'a, [MaybeUninit<T>]> {
#[must_use]
#[inline(always)]
pub(crate) fn uninit_zst_slice(len: usize) -> Self {
assert!(T::IS_ZST);
Self {
ptr: NonNull::slice_from_raw_parts(NonNull::dangling(), len),
marker: PhantomData,
}
}
#[must_use]
#[inline(always)]
pub fn init_fill(self, value: T) -> BumpBox<'a, [T]>
where
T: Clone,
{
unsafe {
let len = self.len();
if len != 0 {
let mut initializer = self.initializer();
for _ in 0..(len - 1) {
initializer.push_unchecked(value.clone());
}
initializer.push_unchecked(value);
initializer.into_init_unchecked()
} else {
BumpBox::default()
}
}
}
#[must_use]
#[inline]
pub fn init_fill_with(self, mut f: impl FnMut() -> T) -> BumpBox<'a, [T]> {
let mut initializer = self.initializer();
while !initializer.is_full() {
initializer.push_with(&mut f);
}
initializer.into_init()
}
#[must_use]
#[inline]
pub fn init_fill_iter(self, mut iter: impl Iterator<Item = T>) -> BumpBox<'a, [T]> {
#[cold]
#[inline(never)]
#[track_caller]
fn iter_ran_out() -> ! {
panic!("iterator ran out of items to fill the slice with");
}
let mut initializer = self.initializer();
while !initializer.is_full() {
match iter.next() {
Some(item) => {
initializer.push(item);
}
None => iter_ran_out(),
}
}
initializer.into_init()
}
#[must_use]
#[inline]
pub fn init_copy(mut self, slice: &[T]) -> BumpBox<'a, [T]>
where
T: Copy,
{
self.copy_from_slice(as_uninit_slice(slice));
unsafe { self.assume_init() }
}
#[must_use]
#[inline]
pub fn init_clone(self, slice: &[T]) -> BumpBox<'a, [T]>
where
T: Clone,
{
assert_eq!(slice.len(), self.len());
let mut initializer = self.initializer();
unsafe {
for value in slice {
initializer.push_unchecked(value.clone());
}
initializer.into_init_unchecked()
}
}
#[inline]
#[must_use]
pub fn init_move(mut self, owned_slice: impl OwnedSlice<Item = T>) -> BumpBox<'a, [T]> {
let mut owned_slice = owned_slice.into_take_owned_slice();
let slice = NonNull::from(owned_slice.owned_slice_ref());
assert_eq!(slice.len(), self.len());
unsafe {
let src = slice.cast::<T>().as_ptr();
let dst = self.as_mut_ptr().cast::<T>();
ptr::copy_nonoverlapping(src, dst, slice.len());
owned_slice.take_owned_slice();
self.assume_init()
}
}
#[must_use]
#[inline]
pub(crate) fn initializer(self) -> BumpBoxSliceInitializer<'a, T> {
BumpBoxSliceInitializer::new(self)
}
#[must_use]
#[inline(always)]
pub unsafe fn assume_init(self) -> BumpBox<'a, [T]> {
let ptr = BumpBox::into_raw(self);
unsafe {
let ptr = NonNull::new_unchecked(ptr.as_ptr() as _);
BumpBox::from_raw(ptr)
}
}
}
impl<'a, T> BumpBox<'a, [T]> {
pub const EMPTY: Self = Self {
ptr: NonNull::slice_from_raw_parts(NonNull::dangling(), 0),
marker: PhantomData,
};
#[must_use]
#[inline(always)]
pub(crate) fn zst_slice_clone(slice: &[T]) -> Self
where
T: Clone,
{
assert!(T::IS_ZST);
BumpBox::uninit_zst_slice(slice.len()).init_clone(slice)
}
#[must_use]
#[inline(always)]
pub(crate) fn zst_slice_fill(len: usize, value: T) -> Self
where
T: Clone,
{
assert!(T::IS_ZST);
if len == 0 {
drop(value);
BumpBox::EMPTY
} else {
for _ in 1..len {
mem::forget(value.clone());
}
mem::forget(value);
unsafe { BumpBox::zst_slice_from_len(len) }
}
}
#[must_use]
#[inline(always)]
pub(crate) fn zst_slice_fill_with(len: usize, f: impl FnMut() -> T) -> Self {
assert!(T::IS_ZST);
BumpBox::uninit_zst_slice(len).init_fill_with(f)
}
#[must_use]
#[inline(always)]
pub(crate) unsafe fn zst_slice_from_len(len: usize) -> Self {
assert!(T::IS_ZST);
Self {
ptr: NonNull::slice_from_raw_parts(NonNull::dangling(), len),
marker: PhantomData,
}
}
#[must_use]
#[inline(always)]
pub const fn len(&self) -> usize {
self.ptr.len()
}
#[must_use]
#[inline(always)]
pub const fn is_empty(&self) -> bool {
self.len() == 0
}
#[inline(always)]
pub fn pop(&mut self) -> Option<T> {
if self.is_empty() {
None
} else {
unsafe {
self.set_len(self.len() - 1);
let ptr = self.as_ptr().add(self.len());
Some(ptr.read())
}
}
}
#[inline(always)]
pub fn clear(&mut self) {
let elems: NonNull<[T]> = self.ptr;
unsafe {
self.set_len(0);
elems.drop_in_place();
}
}
pub fn truncate(&mut self, len: usize) {
unsafe { non_null::truncate(&mut self.ptr, len) }
}
#[must_use]
#[inline(always)]
pub const fn as_slice(&self) -> &[T] {
unsafe { &*self.ptr.as_ptr().cast_const() }
}
#[must_use]
#[inline(always)]
pub fn as_mut_slice(&mut self) -> &mut [T] {
unsafe { self.ptr.as_mut() }
}
#[inline]
#[must_use]
pub fn as_ptr(&self) -> *const T {
self.ptr.as_ptr().cast()
}
#[inline]
pub fn as_mut_ptr(&mut self) -> *mut T {
self.ptr.as_ptr().cast()
}
#[must_use]
#[inline(always)]
pub const fn as_non_null(&self) -> NonNull<T> {
self.ptr.cast()
}
#[inline(always)]
pub(crate) unsafe fn set_ptr(&mut self, new_ptr: NonNull<T>) {
non_null::set_ptr(&mut self.ptr, new_ptr);
}
#[inline]
pub unsafe fn set_len(&mut self, new_len: usize) {
non_null::set_len(&mut self.ptr, new_len);
}
#[inline]
pub(crate) unsafe fn inc_len(&mut self, amount: usize) {
unsafe { self.set_len(self.len() + amount) };
}
#[inline]
pub(crate) unsafe fn dec_len(&mut self, amount: usize) {
unsafe { self.set_len(self.len() - amount) };
}
#[inline(always)]
pub(crate) unsafe fn set_len_on_drop(&mut self) -> SetLenOnDropByPtr<'_, T> {
SetLenOnDropByPtr::new(&mut self.ptr)
}
#[track_caller]
pub fn remove(&mut self, index: usize) -> T {
#[cold]
#[inline(never)]
#[track_caller]
fn assert_failed(index: usize, len: usize) -> ! {
panic!("removal index (is {index}) should be < len (is {len})");
}
if index >= self.len() {
assert_failed(index, self.len());
}
unsafe {
let start = self.as_mut_ptr();
let value_ptr = start.add(index);
let value = value_ptr.read();
if index != self.len() {
let len = self.len() - index - 1;
value_ptr.add(1).copy_to(value_ptr, len);
}
self.dec_len(1);
value
}
}
#[inline]
pub fn swap_remove(&mut self, index: usize) -> T {
#[cold]
#[inline(never)]
#[track_caller]
fn assert_failed(index: usize, len: usize) -> ! {
panic!("swap_remove index (is {index}) should be < len (is {len})");
}
if index >= self.len() {
assert_failed(index, self.len());
}
unsafe {
let start = self.as_mut_ptr();
let value_ptr = start.add(index);
let value = value_ptr.read();
self.dec_len(1);
start.add(self.len()).copy_to(value_ptr, 1);
value
}
}
#[inline]
#[expect(clippy::return_self_not_must_use)]
pub fn split_off(&mut self, range: impl RangeBounds<usize>) -> Self {
let len = self.len();
let ops::Range { start, end } = polyfill::slice::range(range, ..len);
let ptr = non_null::as_non_null_ptr(self.ptr);
if T::IS_ZST {
let range_len = end - start;
let remaining_len = len - range_len;
unsafe {
self.set_len(remaining_len);
return BumpBox::zst_slice_from_len(range_len);
}
}
if end == len {
let lhs = NonNull::slice_from_raw_parts(ptr, start);
let rhs = NonNull::slice_from_raw_parts(unsafe { ptr.add(start) }, len - start);
self.ptr = lhs;
return unsafe { BumpBox::from_raw(rhs) };
}
if start == 0 {
let lhs = NonNull::slice_from_raw_parts(ptr, end);
let rhs = NonNull::slice_from_raw_parts(unsafe { ptr.add(end) }, len - end);
self.ptr = rhs;
return unsafe { BumpBox::from_raw(lhs) };
}
if start == end {
return BumpBox::EMPTY;
}
let head_len = start;
let tail_len = len - end;
let range_len = end - start;
let remaining_len = len - range_len;
unsafe {
if head_len < tail_len {
self.as_mut_slice().get_unchecked_mut(..end).rotate_right(range_len);
let lhs = NonNull::slice_from_raw_parts(ptr, range_len);
let rhs = NonNull::slice_from_raw_parts(ptr.add(range_len), remaining_len);
self.ptr = rhs;
BumpBox::from_raw(lhs)
} else {
self.as_mut_slice().get_unchecked_mut(start..).rotate_left(range_len);
let lhs = NonNull::slice_from_raw_parts(ptr, remaining_len);
let rhs = NonNull::slice_from_raw_parts(ptr.add(remaining_len), range_len);
self.ptr = lhs;
BumpBox::from_raw(rhs)
}
}
}
#[inline]
#[must_use]
pub fn split_off_first(&mut self) -> Option<BumpBox<'a, T>> {
let (first, rest) = mem::take(self).split_first()?;
*self = rest;
Some(first)
}
#[inline]
#[must_use]
pub fn split_off_last(&mut self) -> Option<BumpBox<'a, T>> {
let (last, rest) = mem::take(self).split_last()?;
*self = rest;
Some(last)
}
#[inline]
#[must_use]
pub fn split_at(self, at: usize) -> (Self, Self) {
#[cold]
#[inline(never)]
#[track_caller]
fn assert_failed(at: usize, len: usize) -> ! {
panic!("`at` split index (is {at}) should be <= len (is {len})");
}
if at > self.len() {
assert_failed(at, self.len());
}
unsafe { self.split_at_unchecked(at) }
}
#[inline]
#[must_use]
pub unsafe fn split_at_unchecked(self, mid: usize) -> (Self, Self) {
unsafe {
let this = ManuallyDrop::new(self);
let len = this.len();
let ptr = this.ptr.cast::<T>();
debug_assert!(
mid <= len,
"slice::split_at_unchecked requires the index to be within the slice"
);
(
Self::from_raw(NonNull::slice_from_raw_parts(ptr, mid)),
Self::from_raw(NonNull::slice_from_raw_parts(ptr.add(mid), len - mid)),
)
}
}
#[inline]
#[must_use]
pub fn split_first(self) -> Option<(BumpBox<'a, T>, BumpBox<'a, [T]>)> {
let this = ManuallyDrop::new(self);
if this.is_empty() {
return None;
}
unsafe {
let ptr = this.ptr.cast::<T>();
let len = this.len();
Some((
BumpBox::from_raw(ptr),
BumpBox::from_raw(NonNull::slice_from_raw_parts(ptr.add(1), len - 1)),
))
}
}
#[inline]
#[must_use]
pub fn split_last(self) -> Option<(BumpBox<'a, T>, BumpBox<'a, [T]>)> {
let this = ManuallyDrop::new(self);
if this.is_empty() {
return None;
}
unsafe {
let ptr = this.ptr.cast::<T>();
let len_minus_one = this.len() - 1;
Some((
BumpBox::from_raw(ptr.add(len_minus_one)),
BumpBox::from_raw(NonNull::slice_from_raw_parts(ptr, len_minus_one)),
))
}
}
#[inline]
#[must_use]
pub fn merge(self, other: Self) -> Self {
#[cold]
#[inline(never)]
#[track_caller]
fn assert_failed_zst() -> ! {
panic!("adding the lengths overflowed");
}
#[cold]
#[inline(never)]
#[track_caller]
fn assert_failed() -> ! {
panic!("the two slices are not contiguous");
}
if T::IS_ZST {
let Some(len) = self.len().checked_add(other.len()) else {
assert_failed_zst()
};
let _ = self.into_raw();
let _ = other.into_raw();
unsafe { Self::zst_slice_from_len(len) }
} else {
if self.as_ptr_range().end != other.as_ptr() {
assert_failed();
}
let lhs = self.into_raw();
let rhs = other.into_raw();
let ptr = non_null::as_non_null_ptr(lhs);
let len = lhs.len() + rhs.len();
let slice = NonNull::slice_from_raw_parts(ptr, len);
unsafe { Self::from_raw(slice) }
}
}
#[expect(clippy::pedantic)]
pub fn retain<F>(&mut self, mut f: F)
where
F: FnMut(&mut T) -> bool,
{
let original_len = self.len();
if original_len == 0 {
return;
}
struct PanicGuard<'b, 'a, T> {
v: &'b mut BumpBox<'a, [T]>,
read: usize,
write: usize,
original_len: usize,
}
impl<T> Drop for PanicGuard<'_, '_, T> {
#[cold]
fn drop(&mut self) {
let remaining = self.original_len - self.read;
unsafe {
ptr::copy(self.v.as_ptr().add(self.read), self.v.as_mut_ptr().add(self.write), remaining);
}
unsafe {
self.v.set_len(self.write + remaining);
}
}
}
let mut read = 0;
loop {
let cur = unsafe { self.get_unchecked_mut(read) };
if polyfill::hint::unlikely(!f(cur)) {
break;
}
read += 1;
if read == original_len {
return;
}
}
let mut g = PanicGuard {
v: self,
read: read + 1,
write: read,
original_len,
};
unsafe { ptr::drop_in_place(&mut *g.v.as_mut_ptr().add(read)) };
while g.read < g.original_len {
let cur = unsafe { &mut *g.v.as_mut_ptr().add(g.read) };
if !f(cur) {
g.read += 1;
unsafe { ptr::drop_in_place(cur) };
} else {
unsafe {
let hole = g.v.as_mut_ptr().add(g.write);
ptr::copy_nonoverlapping(cur, hole, 1);
}
g.write += 1;
g.read += 1;
}
}
unsafe { g.v.set_len(g.write) };
mem::forget(g);
}
pub fn drain<R>(&mut self, range: R) -> owned_slice::Drain<'_, T>
where
R: RangeBounds<usize>,
{
owned_slice::Drain::new(self, range)
}
pub fn extract_if<F>(&mut self, filter: F) -> owned_slice::ExtractIf<'_, T, F>
where
F: FnMut(&mut T) -> bool,
{
owned_slice::ExtractIf::new(self, filter)
}
#[inline]
pub fn dedup(&mut self)
where
T: PartialEq,
{
self.dedup_by(|a, b| a == b);
}
#[inline]
pub fn dedup_by_key<F, K>(&mut self, mut key: F)
where
F: FnMut(&mut T) -> K,
K: PartialEq,
{
self.dedup_by(|a, b| key(a) == key(b));
}
pub fn dedup_by<F>(&mut self, mut same_bucket: F)
where
F: FnMut(&mut T, &mut T) -> bool,
{
let len = self.len();
if len <= 1 {
return;
}
struct FillGapOnDrop<'b, 'a, T> {
read: usize,
write: usize,
boxed: &'b mut BumpBox<'a, [T]>,
}
impl<T> Drop for FillGapOnDrop<'_, '_, T> {
fn drop(&mut self) {
unsafe {
let ptr = self.boxed.as_mut_ptr();
let len = self.boxed.len();
let items_left = len.wrapping_sub(self.read);
let dropped_ptr = ptr.add(self.write);
let valid_ptr = ptr.add(self.read);
ptr::copy(valid_ptr, dropped_ptr, items_left);
let dropped = self.read.wrapping_sub(self.write);
self.boxed.set_len(len - dropped);
}
}
}
let mut gap = FillGapOnDrop {
read: 1,
write: 1,
boxed: self,
};
let ptr = gap.boxed.as_mut_ptr();
unsafe {
while gap.read < len {
let read_ptr = ptr.add(gap.read);
let prev_ptr = ptr.add(gap.write.wrapping_sub(1));
if same_bucket(&mut *read_ptr, &mut *prev_ptr) {
gap.read += 1;
ptr::drop_in_place(read_ptr);
} else {
let write_ptr = ptr.add(gap.write);
ptr::copy(read_ptr, write_ptr, 1);
gap.write += 1;
gap.read += 1;
}
}
gap.boxed.set_len(gap.write);
mem::forget(gap);
}
}
pub fn partition<F>(mut self, f: F) -> (Self, Self)
where
F: FnMut(&T) -> bool,
{
let index = polyfill::iter::partition_in_place(self.iter_mut(), f);
self.split_at(index)
}
pub fn map_in_place<U>(self, mut f: impl FnMut(T) -> U) -> BumpBox<'a, [U]> {
assert_in_place_mappable!(T, U);
if U::IS_ZST {
return BumpBox::uninit_zst_slice(self.len()).init_fill_iter(self.into_iter().map(f));
}
struct DropGuard<T, U> {
ptr: NonNull<T>,
end: *mut T,
src: *mut T,
dst: *mut U,
}
impl<T, U> Drop for DropGuard<T, U> {
fn drop(&mut self) {
unsafe {
let drop_ptr = self.src.add(1);
let drop_len = pointer::offset_from_unsigned(self.end, drop_ptr);
ptr::slice_from_raw_parts_mut(drop_ptr, drop_len).drop_in_place();
let drop_ptr = self.ptr.cast::<U>().as_ptr();
let drop_len = pointer::offset_from_unsigned(self.dst, drop_ptr);
ptr::slice_from_raw_parts_mut(drop_ptr, drop_len).drop_in_place();
}
}
}
let slice = self.into_raw();
let ptr = slice.cast::<T>();
let len = slice.len();
unsafe {
let mut guard = DropGuard::<T, U> {
ptr,
end: ptr.as_ptr().add(len),
src: ptr.as_ptr(),
dst: ptr.as_ptr().cast::<U>(),
};
while guard.src < guard.end {
let src_value = guard.src.read();
let dst_value = f(src_value);
guard.dst.write(dst_value);
guard.src = guard.src.add(1);
guard.dst = guard.dst.add(1);
}
mem::forget(guard);
BumpBox::from_raw(NonNull::slice_from_raw_parts(ptr.cast(), len))
}
}
}
impl<'a, T, const N: usize> BumpBox<'a, [[T; N]]> {
#[must_use]
pub fn into_flattened(self) -> BumpBox<'a, [T]> {
let ptr = self.into_raw();
let len = ptr.len();
let new_len = if T::IS_ZST {
len.checked_mul(N).expect("slice len overflow")
} else {
unsafe { len.unchecked_mul(N) }
};
unsafe { BumpBox::from_raw(NonNull::slice_from_raw_parts(ptr.cast(), new_len)) }
}
}
impl<'a> BumpBox<'a, dyn Any> {
#[inline(always)]
#[expect(clippy::missing_errors_doc)]
pub fn downcast<T: Any>(self) -> Result<BumpBox<'a, T>, Self> {
if self.is::<T>() {
Ok(unsafe { self.downcast_unchecked() })
} else {
Err(self)
}
}
#[must_use]
#[inline(always)]
pub unsafe fn downcast_unchecked<T: Any>(self) -> BumpBox<'a, T> {
debug_assert!(self.is::<T>());
unsafe { BumpBox::from_raw(BumpBox::into_raw(self).cast()) }
}
}
impl<'a> BumpBox<'a, dyn Any + Send> {
#[expect(clippy::missing_errors_doc)]
#[inline(always)]
pub fn downcast<T: Any>(self) -> Result<BumpBox<'a, T>, Self> {
if self.is::<T>() {
Ok(unsafe { self.downcast_unchecked() })
} else {
Err(self)
}
}
#[must_use]
#[inline(always)]
pub unsafe fn downcast_unchecked<T: Any>(self) -> BumpBox<'a, T> {
debug_assert!(self.is::<T>());
unsafe { BumpBox::from_raw(BumpBox::into_raw(self).cast()) }
}
}
impl<'a> BumpBox<'a, dyn Any + Send + Sync> {
#[expect(clippy::missing_errors_doc)]
#[inline(always)]
pub fn downcast<T: Any>(self) -> Result<BumpBox<'a, T>, Self> {
if self.is::<T>() {
Ok(unsafe { self.downcast_unchecked() })
} else {
Err(self)
}
}
#[must_use]
#[inline(always)]
pub unsafe fn downcast_unchecked<T: Any>(self) -> BumpBox<'a, T> {
debug_assert!(self.is::<T>());
unsafe { BumpBox::from_raw(BumpBox::into_raw(self).cast()) }
}
}
impl<T: ?Sized> Unpin for BumpBox<'_, T> {}
#[cfg(feature = "nightly-coerce-unsized")]
impl<'a, T, U> core::ops::CoerceUnsized<BumpBox<'a, U>> for BumpBox<'a, T>
where
T: ?Sized + core::marker::Unsize<U>,
U: ?Sized,
{
}
#[cfg(feature = "nightly-dropck-eyepatch")]
unsafe impl<#[may_dangle] T: ?Sized> Drop for BumpBox<'_, T> {
#[inline(always)]
fn drop(&mut self) {
unsafe { self.ptr.drop_in_place() }
}
}
#[cfg(not(feature = "nightly-dropck-eyepatch"))]
impl<T: ?Sized> Drop for BumpBox<'_, T> {
#[inline(always)]
fn drop(&mut self) {
unsafe { self.ptr.drop_in_place() }
}
}
impl<T> NoDrop for BumpBox<'_, T> where T: NoDrop {}
impl<T: ?Sized> Deref for BumpBox<'_, T> {
type Target = T;
#[inline(always)]
fn deref(&self) -> &Self::Target {
unsafe { self.ptr.as_ref() }
}
}
impl<T: ?Sized> DerefMut for BumpBox<'_, T> {
#[inline(always)]
fn deref_mut(&mut self) -> &mut Self::Target {
unsafe { self.ptr.as_mut() }
}
}
impl<T: ?Sized> AsRef<T> for BumpBox<'_, T> {
#[inline(always)]
fn as_ref(&self) -> &T {
self
}
}
impl<T: ?Sized> AsMut<T> for BumpBox<'_, T> {
#[inline(always)]
fn as_mut(&mut self) -> &mut T {
self
}
}
impl<T: ?Sized> Borrow<T> for BumpBox<'_, T> {
#[inline(always)]
fn borrow(&self) -> &T {
self
}
}
impl<T: ?Sized> BorrowMut<T> for BumpBox<'_, T> {
#[inline(always)]
fn borrow_mut(&mut self) -> &mut T {
self
}
}
impl<T: ?Sized + Debug> Debug for BumpBox<'_, T> {
#[inline(always)]
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
T::fmt(self, f)
}
}
impl<T: ?Sized + Display> Display for BumpBox<'_, T> {
#[inline(always)]
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
T::fmt(self, f)
}
}
impl<T> Default for BumpBox<'_, [T]> {
#[inline(always)]
fn default() -> Self {
unsafe { Self::from_raw(NonNull::from(&mut [])) }
}
}
impl Default for BumpBox<'_, str> {
#[inline(always)]
fn default() -> Self {
unsafe { Self::from_raw(NonNull::from(core::str::from_utf8_unchecked_mut(&mut []))) }
}
}
impl<'b, T: ?Sized + PartialEq> PartialEq<BumpBox<'b, T>> for BumpBox<'_, T> {
#[inline(always)]
fn eq(&self, other: &BumpBox<'b, T>) -> bool {
T::eq(self, other)
}
#[inline(always)]
fn ne(&self, other: &BumpBox<'b, T>) -> bool {
T::ne(self, other)
}
}
impl<T: ?Sized + PartialEq> PartialEq<T> for BumpBox<'_, T> {
#[inline(always)]
fn eq(&self, other: &T) -> bool {
T::eq(self, other)
}
#[inline(always)]
fn ne(&self, other: &T) -> bool {
T::ne(self, other)
}
}
impl<T: ?Sized + PartialEq> PartialEq<&T> for BumpBox<'_, T> {
#[inline(always)]
fn eq(&self, other: &&T) -> bool {
T::eq(self, other)
}
#[inline(always)]
fn ne(&self, other: &&T) -> bool {
T::ne(self, other)
}
}
impl<T: ?Sized + PartialEq> PartialEq<&mut T> for BumpBox<'_, T> {
#[inline(always)]
fn eq(&self, other: &&mut T) -> bool {
T::eq(self, other)
}
#[inline(always)]
fn ne(&self, other: &&mut T) -> bool {
T::ne(self, other)
}
}
impl<'a, T, U> PartialEq<BumpBox<'a, [U]>> for [T]
where
T: PartialEq<U>,
{
#[inline(always)]
fn eq(&self, other: &BumpBox<'a, [U]>) -> bool {
<[T] as PartialEq<[U]>>::eq(self, other)
}
#[inline(always)]
fn ne(&self, other: &BumpBox<'a, [U]>) -> bool {
<[T] as PartialEq<[U]>>::ne(self, other)
}
}
impl<'a, T, U> PartialEq<BumpBox<'a, [U]>> for &[T]
where
T: PartialEq<U>,
{
#[inline(always)]
fn eq(&self, other: &BumpBox<'a, [U]>) -> bool {
<[T] as PartialEq<[U]>>::eq(self, other)
}
#[inline(always)]
fn ne(&self, other: &BumpBox<'a, [U]>) -> bool {
<[T] as PartialEq<[U]>>::ne(self, other)
}
}
impl<'a, T, U> PartialEq<BumpBox<'a, [U]>> for &mut [T]
where
T: PartialEq<U>,
{
#[inline(always)]
fn eq(&self, other: &BumpBox<'a, [U]>) -> bool {
<[T] as PartialEq<[U]>>::eq(self, other)
}
#[inline(always)]
fn ne(&self, other: &BumpBox<'a, [U]>) -> bool {
<[T] as PartialEq<[U]>>::ne(self, other)
}
}
impl<T: PartialEq, const N: usize> PartialEq<[T; N]> for BumpBox<'_, [T]> {
#[inline(always)]
fn eq(&self, other: &[T; N]) -> bool {
<[T]>::eq(self, other)
}
#[inline(always)]
fn ne(&self, other: &[T; N]) -> bool {
<[T]>::ne(self, other)
}
}
impl<'b, T: ?Sized + PartialOrd> PartialOrd<BumpBox<'b, T>> for BumpBox<'_, T> {
#[inline(always)]
fn partial_cmp(&self, other: &BumpBox<'b, T>) -> Option<Ordering> {
T::partial_cmp(self, other)
}
#[inline(always)]
fn lt(&self, other: &BumpBox<'b, T>) -> bool {
T::lt(self, other)
}
#[inline(always)]
fn le(&self, other: &BumpBox<'b, T>) -> bool {
T::le(self, other)
}
#[inline(always)]
fn ge(&self, other: &BumpBox<'b, T>) -> bool {
T::ge(self, other)
}
#[inline(always)]
fn gt(&self, other: &BumpBox<'b, T>) -> bool {
T::gt(self, other)
}
}
impl<'a, T: ?Sized + Ord> Ord for BumpBox<'a, T> {
#[inline(always)]
fn cmp(&self, other: &BumpBox<'a, T>) -> Ordering {
T::cmp(self, other)
}
}
impl<T: ?Sized + Eq> Eq for BumpBox<'_, T> {}
impl<T: ?Sized + Hash> Hash for BumpBox<'_, T> {
#[inline(always)]
fn hash<H: Hasher>(&self, state: &mut H) {
T::hash(self, state);
}
}
impl<T: ?Sized + Hasher> Hasher for BumpBox<'_, T> {
#[inline(always)]
fn finish(&self) -> u64 {
T::finish(self)
}
#[inline(always)]
fn write(&mut self, bytes: &[u8]) {
T::write(self, bytes);
}
#[inline(always)]
fn write_u8(&mut self, i: u8) {
T::write_u8(self, i);
}
#[inline(always)]
fn write_u16(&mut self, i: u16) {
T::write_u16(self, i);
}
#[inline(always)]
fn write_u32(&mut self, i: u32) {
T::write_u32(self, i);
}
#[inline(always)]
fn write_u64(&mut self, i: u64) {
T::write_u64(self, i);
}
#[inline(always)]
fn write_u128(&mut self, i: u128) {
T::write_u128(self, i);
}
#[inline(always)]
fn write_usize(&mut self, i: usize) {
T::write_usize(self, i);
}
#[inline(always)]
fn write_i8(&mut self, i: i8) {
T::write_i8(self, i);
}
#[inline(always)]
fn write_i16(&mut self, i: i16) {
T::write_i16(self, i);
}
#[inline(always)]
fn write_i32(&mut self, i: i32) {
T::write_i32(self, i);
}
#[inline(always)]
fn write_i64(&mut self, i: i64) {
T::write_i64(self, i);
}
#[inline(always)]
fn write_i128(&mut self, i: i128) {
T::write_i128(self, i);
}
#[inline(always)]
fn write_isize(&mut self, i: isize) {
T::write_isize(self, i);
}
}
#[cfg(feature = "alloc")]
impl<'a> Extend<BumpBox<'a, str>> for alloc_crate::string::String {
#[inline(always)]
fn extend<T: IntoIterator<Item = BumpBox<'a, str>>>(&mut self, iter: T) {
iter.into_iter().for_each(move |s| self.push_str(&s));
}
}
impl<'a, T> IntoIterator for BumpBox<'a, [T]> {
type Item = T;
type IntoIter = owned_slice::IntoIter<'a, T>;
#[inline(always)]
fn into_iter(self) -> Self::IntoIter {
let this = ManuallyDrop::new(self);
unsafe { owned_slice::IntoIter::new(this.ptr) }
}
}
impl<'b, T> IntoIterator for &'b BumpBox<'_, [T]> {
type Item = &'b T;
type IntoIter = slice::Iter<'b, T>;
#[inline(always)]
fn into_iter(self) -> Self::IntoIter {
<[T]>::iter(self)
}
}
impl<'b, T> IntoIterator for &'b mut BumpBox<'_, [T]> {
type Item = &'b mut T;
type IntoIter = slice::IterMut<'b, T>;
#[inline(always)]
fn into_iter(self) -> Self::IntoIter {
<[T]>::iter_mut(self)
}
}
impl<I, T: Index<I>> Index<I> for BumpBox<'_, T> {
type Output = <T as Index<I>>::Output;
#[inline]
fn index(&self, index: I) -> &Self::Output {
<T as Index<I>>::index(self, index)
}
}
impl<I, T: IndexMut<I>> IndexMut<I> for BumpBox<'_, T> {
#[inline]
fn index_mut(&mut self, index: I) -> &mut Self::Output {
<T as IndexMut<I>>::index_mut(self, index)
}
}
#[cfg(feature = "std")]
impl<T: ?Sized + std::io::Read> std::io::Read for BumpBox<'_, T> {
#[inline(always)]
fn read(&mut self, buf: &mut [u8]) -> std::io::Result<usize> {
T::read(self, buf)
}
#[inline(always)]
fn read_vectored(&mut self, bufs: &mut [std::io::IoSliceMut<'_>]) -> std::io::Result<usize> {
T::read_vectored(self, bufs)
}
#[inline(always)]
fn read_to_end(&mut self, buf: &mut Vec<u8>) -> std::io::Result<usize> {
T::read_to_end(self, buf)
}
#[inline(always)]
fn read_to_string(&mut self, buf: &mut String) -> std::io::Result<usize> {
T::read_to_string(self, buf)
}
#[inline(always)]
fn read_exact(&mut self, buf: &mut [u8]) -> std::io::Result<()> {
T::read_exact(self, buf)
}
}
#[cfg(feature = "std")]
impl<T: ?Sized + std::io::Write> std::io::Write for BumpBox<'_, T> {
#[inline(always)]
fn write(&mut self, buf: &[u8]) -> std::io::Result<usize> {
T::write(self, buf)
}
#[inline(always)]
fn write_vectored(&mut self, bufs: &[std::io::IoSlice<'_>]) -> std::io::Result<usize> {
T::write_vectored(self, bufs)
}
#[inline(always)]
fn flush(&mut self) -> std::io::Result<()> {
T::flush(self)
}
#[inline(always)]
fn write_all(&mut self, buf: &[u8]) -> std::io::Result<()> {
T::write_all(self, buf)
}
#[inline(always)]
fn write_fmt(&mut self, fmt: std::fmt::Arguments<'_>) -> std::io::Result<()> {
T::write_fmt(self, fmt)
}
}
#[cfg(feature = "std")]
impl<T: ?Sized + std::io::Seek> std::io::Seek for BumpBox<'_, T> {
#[inline(always)]
fn seek(&mut self, pos: std::io::SeekFrom) -> std::io::Result<u64> {
T::seek(self, pos)
}
#[inline(always)]
fn stream_position(&mut self) -> std::io::Result<u64> {
T::stream_position(self)
}
}
#[cfg(feature = "std")]
impl<T: ?Sized + std::io::BufRead> std::io::BufRead for BumpBox<'_, T> {
#[inline(always)]
fn fill_buf(&mut self) -> std::io::Result<&[u8]> {
T::fill_buf(self)
}
#[inline(always)]
fn consume(&mut self, amt: usize) {
T::consume(self, amt);
}
#[inline(always)]
fn read_until(&mut self, byte: u8, buf: &mut std::vec::Vec<u8>) -> std::io::Result<usize> {
T::read_until(self, byte, buf)
}
#[inline(always)]
fn read_line(&mut self, buf: &mut std::string::String) -> std::io::Result<usize> {
T::read_line(self, buf)
}
}
#[cfg(feature = "nightly-fn-traits")]
impl<Args: Tuple, F: FnOnce<Args> + ?Sized> FnOnce<Args> for BumpBox<'_, F> {
type Output = <F as FnOnce<Args>>::Output;
extern "rust-call" fn call_once(self, args: Args) -> Self::Output {
use alloc_crate::{
alloc::{AllocError, Allocator},
boxed::Box,
};
struct NoopAllocator;
unsafe impl Allocator for NoopAllocator {
fn allocate(&self, _layout: Layout) -> Result<NonNull<[u8]>, AllocError> {
Err(AllocError)
}
unsafe fn deallocate(&self, _ptr: NonNull<u8>, _layout: Layout) {}
}
let ptr = self.into_raw().as_ptr();
unsafe {
let boxed = Box::from_raw_in(ptr, NoopAllocator);
<Box<F, NoopAllocator> as FnOnce<Args>>::call_once(boxed, args)
}
}
}
#[cfg(feature = "nightly-fn-traits")]
impl<Args: Tuple, F: FnMut<Args> + ?Sized> FnMut<Args> for BumpBox<'_, F> {
extern "rust-call" fn call_mut(&mut self, args: Args) -> Self::Output {
<F as FnMut<Args>>::call_mut(self, args)
}
}
#[cfg(feature = "nightly-fn-traits")]
impl<Args: Tuple, F: Fn<Args> + ?Sized> Fn<Args> for BumpBox<'_, F> {
extern "rust-call" fn call(&self, args: Args) -> Self::Output {
<F as Fn<Args>>::call(self, args)
}
}
#[inline(always)]
fn as_uninit_slice<T>(slice: &[T]) -> &[MaybeUninit<T>] {
unsafe { &*(ptr::from_ref(slice) as *const [MaybeUninit<T>]) }
}
macro_rules! assert_in_place_mappable {
($src:ty, $dst:ty) => {
let _assert = AssertInPlaceMappable::<$src, $dst>::ASSERT;
};
}
#[expect(clippy::useless_attribute)]
#[expect(clippy::needless_pub_self)]
pub(self) use assert_in_place_mappable;
struct AssertInPlaceMappable<Src, Dst>(PhantomData<(Src, Dst)>);
impl<Src, Dst> AssertInPlaceMappable<Src, Dst> {
const ASSERT: () = assert!(
Dst::IS_ZST || (Src::ALIGN >= Dst::ALIGN && Src::SIZE >= Dst::SIZE),
"`map_in_place` only compiles when `U`s size and alignment is less or equal to `T`'s or if `U` has a size of 0"
);
}
const _: () = {
#[repr(align(1024))]
struct AlignedZst;
assert_in_place_mappable!(u32, u32);
assert_in_place_mappable!(u32, Option<core::num::NonZeroU32>);
assert_in_place_mappable!(u32, [u8; 4]);
assert_in_place_mappable!(u32, [u16; 2]);
assert_in_place_mappable!(u32, ());
assert_in_place_mappable!(u32, AlignedZst);
assert_in_place_mappable!((), ());
assert_in_place_mappable!((), AlignedZst);
};