#![allow(clippy::assertions_on_result_states, reason = "test code")]
#![allow(clippy::empty_drop, reason = "test code: probe types use empty Drop on purpose")]
#![allow(clippy::items_after_statements, reason = "test code: local helpers stay near their use")]
#![allow(clippy::zst_offset, reason = "test code: ZST drop-probe offsets are just for type-checking")]
#![allow(clippy::needless_borrow, reason = "test code")]
#![allow(clippy::needless_borrows_for_generic_args, reason = "test code")]
#![allow(clippy::large_stack_arrays, reason = "test code: oversized blob test probes the >64 KiB path")]
use allocator_api2::alloc::Global;
#[cfg(feature = "dst")]
use super::align_up;
use super::{AllocFlavor, align_offset, check_isize_overflow};
#[allow(unused_imports, reason = "kept for documentation in test comments")]
use crate::internal::constants::MAX_CHUNK_BYTES;
#[cfg(feature = "stats")]
use crate::internal::constants::MIN_MAX_NORMAL_ALLOC;
use crate::internal::drop_list::noop_drop_shim;
#[cfg(feature = "std")]
use crate::internal::drop_list::{drop_shim_one, drop_shim_slice};
use crate::{Arc, Arena};
#[test]
fn slice_reservation_debug_format() {
check_isize_overflow(100, 8).expect("100 bytes fits");
assert!(check_isize_overflow(isize::MAX as usize, 8).is_err());
}
#[test]
fn reserve_slice_rejects_excessive_alignment() {
let arena = Arena::new();
let _slice = arena.try_alloc_slice_copy([1u8, 2, 3]).expect("3-byte u8 slice fits");
}
#[test]
fn alloc_arc_then_clone_reads_value_through_both_handles() {
let arena = Arena::new();
let a1 = arena.alloc_arc(42u64);
assert_eq!(*a1, 42);
let a2 = Arc::clone(&a1);
assert_eq!(*a2, 42);
}
#[test]
fn arena_inner_debug_format() {
let arena = Arena::new();
let _ = alloc::format!("{arena:?}");
}
#[test]
#[expect(
clippy::large_stack_arrays,
reason = "deliberate oversized-chunk allocation; the array is moved into the arena, not retained on the stack"
)]
fn inc_ref_shared_deferred_oversized_path() {
let arena = Arena::new();
let big = arena.alloc_arc([0u8; 65536]);
let big2 = big.clone();
assert_eq!(big[0], big2[0]);
}
#[cfg(feature = "dst")]
#[test]
fn inc_ref_shared_deferred_reconcile_via_dst() {
let arena = Arena::new();
let a = arena.alloc_arc(99u32);
assert_eq!(*a, 99);
}
#[test]
fn evicted_chunk_guard_debug() {
let arena = Arena::new();
for i in 0..1000u64 {
arena.alloc(i);
}
}
#[test]
fn align_offset_padding_to_next_boundary() {
assert_eq!(align_offset(0, 8), Some(0));
assert_eq!(align_offset(1, 8), Some(7));
assert_eq!(align_offset(7, 8), Some(1));
assert_eq!(align_offset(8, 8), Some(0));
assert_eq!(align_offset(9, 8), Some(7));
assert_eq!(align_offset(15, 8), Some(1));
}
#[test]
fn align_offset_returns_none_on_overflow() {
assert!(align_offset(usize::MAX, 8).is_none());
assert!(align_offset(usize::MAX - 6, 8).is_none());
assert!(align_offset(usize::MAX - 7, 8).is_some());
}
#[test]
fn local_chunk_header_size_is_offset_plus_size() {
use crate::internal::local_chunk::{LocalChunk, header_size};
let drop_count_offset = core::mem::offset_of!(LocalChunk<Global>, drop_count);
let drop_count_size = core::mem::size_of::<core::cell::Cell<u16>>();
assert_eq!(header_size::<Global>(), drop_count_offset + drop_count_size);
assert!(header_size::<Global>() < 2 * drop_count_offset);
}
#[test]
fn shared_chunk_header_size_is_offset_plus_size() {
use crate::internal::shared_chunk::{SharedChunk, header_size};
use crate::internal::sync::AtomicU16;
let drop_count_offset = core::mem::offset_of!(SharedChunk<Global>, drop_count);
let drop_count_size = core::mem::size_of::<AtomicU16>();
assert_eq!(header_size::<Global>(), drop_count_offset + drop_count_size);
assert!(header_size::<Global>() < 2 * drop_count_offset);
}
#[test]
fn local_chunk_allocate_total_smaller_than_header_returns_err() {
use alloc::sync::Weak;
use crate::internal::local_chunk::{LocalChunk, header_size};
let header = header_size::<Global>();
let result = LocalChunk::<Global>::allocate(Global, Weak::new(), header.saturating_sub(1));
assert!(result.is_err(), "total_bytes < header_size must be rejected");
}
#[test]
fn local_chunk_allocate_total_equal_to_header_returns_ok() {
use alloc::sync::Weak;
use crate::internal::local_chunk::{LocalChunk, header_size};
let header = header_size::<Global>();
let chunk = LocalChunk::<Global>::allocate(Global, Weak::new(), header).expect("zero-payload chunk should allocate");
unsafe {
(*chunk.as_ptr()).refcount.set(0);
LocalChunk::<Global>::free_backing(chunk);
}
}
#[test]
fn shared_chunk_allocate_total_smaller_than_header_returns_err() {
use alloc::sync::Weak;
use crate::internal::shared_chunk::{SharedChunk, header_size};
let header = header_size::<Global>();
let result = SharedChunk::<Global>::allocate(Global, Weak::new(), header.saturating_sub(1));
assert!(result.is_err(), "total_bytes < header_size must be rejected");
}
#[test]
fn shared_chunk_allocate_total_equal_to_header_returns_ok() {
use alloc::sync::Weak;
use crate::internal::shared_chunk::{SharedChunk, header_size};
use crate::internal::sync::Ordering;
let header = header_size::<Global>();
let chunk = SharedChunk::<Global>::allocate(Global, Weak::new(), header).expect("zero-payload chunk should allocate");
unsafe {
(*chunk.as_ptr()).refcount.0.store(0, Ordering::Relaxed);
SharedChunk::<Global>::free_backing(chunk);
}
}
#[test]
fn refill_shared_at_max_chunk_bytes_boundary() {
let arena = Arena::<Global>::new();
let upper = crate::internal::shared_chunk::max_bump_extent::<Global>();
assert!(
arena.refill_shared(upper).is_ok(),
"max_bump_extent is the largest accepted refill request"
);
let arena2 = Arena::<Global>::new();
assert!(
arena2.refill_shared(upper + 1).is_err(),
"one byte past max_bump_extent must be rejected"
);
}
#[test]
fn refill_local_at_max_chunk_bytes_boundary() {
let arena = Arena::<Global>::new();
let upper = crate::internal::local_chunk::max_bump_extent::<Global>();
assert!(
arena.refill_local(upper).is_ok(),
"max_bump_extent is the largest accepted refill request"
);
let arena2 = Arena::<Global>::new();
assert!(
arena2.refill_local(upper + 1).is_err(),
"one byte past max_bump_extent must be rejected"
);
}
#[cfg(feature = "std")]
#[test]
fn alloc_slice_local_with_or_panic_partial_init_drops_partial() {
use core::cell::Cell;
use std::panic::AssertUnwindSafe;
struct D<'a>(&'a Cell<u32>);
impl Drop for D<'_> {
fn drop(&mut self) {
self.0.set(self.0.get() + 1);
}
}
let drops = Cell::new(0_u32);
let arena = Arena::<Global>::new();
let result = std::panic::catch_unwind(AssertUnwindSafe(|| {
let _ = arena.alloc_slice_local_with_or_panic::<D<'_>, _>(64, AllocFlavor::SimpleRef, Some(drop_shim_one::<D<'_>>), |i, slot| {
assert!(i != 17, "synthetic init panic");
slot.write(D(&drops));
});
}));
assert!(result.is_err());
assert_eq!(drops.get(), 17, "init guard must drop exactly the written prefix");
drop(arena);
}
#[cfg(feature = "std")]
#[test]
fn alloc_slice_shared_with_or_panic_partial_init_drops_partial() {
use std::panic::AssertUnwindSafe;
use std::sync::Arc as StdArc;
use std::sync::atomic::{AtomicU32, Ordering as StdOrdering};
struct D(StdArc<AtomicU32>);
impl Drop for D {
fn drop(&mut self) {
self.0.fetch_add(1, StdOrdering::Relaxed);
}
}
let drops = StdArc::new(AtomicU32::new(0));
let arena = Arena::<Global>::new();
let drops_ref = StdArc::clone(&drops);
let result = std::panic::catch_unwind(AssertUnwindSafe(|| {
let _ = arena.alloc_slice_shared_with_or_panic::<D, _>(64, Some(drop_shim_one::<D>), |i, slot| {
assert!(i != 17, "synthetic init panic");
slot.write(D(StdArc::clone(&drops_ref)));
});
}));
assert!(result.is_err());
assert_eq!(drops.load(StdOrdering::Relaxed), 17);
drop(arena);
}
#[test]
fn alloc_slice_local_with_or_panic_no_drop_fn_does_not_reserve_drop_entry() {
let arena = Arena::<Global>::new();
let _ = arena.alloc::<u32>(0);
let drop_back_before = arena.current_local.drop_back.get();
let _ = arena.alloc_slice_local_with_or_panic::<u32, _>(10, AllocFlavor::SimpleRef, None, |_, slot| {
slot.write(0);
});
let drop_back_after = arena.current_local.drop_back.get();
assert_eq!(
drop_back_before, drop_back_after,
"drop_back must not retreat when no drop entry is reserved"
);
}
#[test]
fn alloc_slice_shared_with_or_panic_empty_drop_type_does_not_reserve_drop_entry() {
let arena = Arena::<Global>::new();
let _ = arena.alloc_arc(0_u32);
let drop_back_before = arena.current_shared.drop_back.get();
let raw = arena.alloc_slice_shared_with_or_panic::<u8, _>(0, Some(noop_drop_shim), |_, slot| {
slot.write(0);
});
let drop_back_after = arena.current_shared.drop_back.get();
let _arc: crate::Arc<[u8], Global> = unsafe { crate::Arc::from_value_ptr(raw) };
assert_eq!(
drop_back_before, drop_back_after,
"drop_back must not retreat for empty slice even with drop_fn"
);
}
#[test]
fn alloc_slice_shared_with_or_panic_no_drop_fn_does_not_reserve_drop_entry() {
let arena = Arena::<Global>::new();
let _ = arena.alloc_arc(0_u32);
let drop_back_before = arena.current_shared.drop_back.get();
let raw = arena.alloc_slice_shared_with_or_panic::<u32, _>(10, None, |_, slot| {
slot.write(0);
});
let drop_back_after = arena.current_shared.drop_back.get();
let _arc: crate::Arc<[u32], Global> = unsafe { crate::Arc::from_value_ptr(raw) };
assert_eq!(
drop_back_before, drop_back_after,
"drop_back must not retreat when no drop entry is reserved"
);
}
#[test]
fn alloc_slice_local_with_or_panic_at_u16_max_succeeds() {
let arena = Arena::<Global>::builder().max_normal_alloc(60 * 1024).build();
let ptr = arena.alloc_slice_local_with_or_panic::<u8, _>(u16::MAX as usize, AllocFlavor::SimpleRef, Some(noop_drop_shim), |_, slot| {
slot.write(0);
});
assert_eq!(ptr.len(), u16::MAX as usize);
}
#[test]
fn alloc_slice_shared_with_or_panic_at_u16_max_succeeds() {
let arena = Arena::<Global>::builder().max_normal_alloc(60 * 1024).build();
let raw = arena.alloc_slice_shared_with_or_panic::<u8, _>(u16::MAX as usize, Some(noop_drop_shim), |_, slot| {
slot.write(0);
});
assert_eq!(raw.len(), u16::MAX as usize);
let _arc: crate::Arc<[u8], Global> = unsafe { crate::Arc::from_value_ptr(raw) };
}
#[cfg(feature = "stats")]
#[test]
fn alloc_slice_local_with_or_panic_at_max_normal_uses_fast_path() {
let arena = Arena::<Global>::builder()
.max_normal_alloc(MIN_MAX_NORMAL_ALLOC)
.with_capacity_local(64 * 1024)
.build();
let _ = arena.alloc::<u8>(0);
let before = arena.stats().normal_local_chunks_allocated;
let _ = arena.alloc_slice_local_with_or_panic::<u64, _>(MIN_MAX_NORMAL_ALLOC / 8, AllocFlavor::SimpleRef, None, |_, slot| {
slot.write(0);
});
let after = arena.stats().normal_local_chunks_allocated;
assert_eq!(before, after, "exact max_normal_alloc must not need a new chunk");
}
#[cfg(feature = "stats")]
#[test]
fn alloc_slice_shared_with_or_panic_at_max_normal_uses_fast_path() {
let arena = Arena::<Global>::builder()
.max_normal_alloc(MIN_MAX_NORMAL_ALLOC)
.with_capacity_shared(64 * 1024)
.build();
let _ = arena.alloc_arc::<u8>(0);
let before = arena.stats().normal_shared_chunks_allocated;
let raw = arena.alloc_slice_shared_with_or_panic::<u64, _>(MIN_MAX_NORMAL_ALLOC / 8, None, |_, slot| {
slot.write(0);
});
let after = arena.stats().normal_shared_chunks_allocated;
let _arc: crate::Arc<[u64], Global> = unsafe { crate::Arc::from_value_ptr(raw) };
assert_eq!(before, after, "exact max_normal_alloc must not need a new chunk");
}
#[cfg(feature = "std")]
#[test]
fn alloc_slice_local_with_or_panic_no_drop_large_len_succeeds() {
let arena = Arena::<Global>::default();
let res = std::panic::catch_unwind(std::panic::AssertUnwindSafe(|| {
let _ = arena.alloc_slice_local_with_or_panic::<u8, _>(u16::MAX as usize + 1, AllocFlavor::SimpleRef, None, |_, slot| {
slot.write(0);
});
}));
assert!(res.is_ok(), "no drop_fn ⇒ no u16::MAX cap, must not panic");
}
#[cfg(feature = "std")]
#[test]
fn alloc_slice_shared_with_or_panic_no_drop_large_len_succeeds() {
let arena = Arena::<Global>::default();
let res = std::panic::catch_unwind(std::panic::AssertUnwindSafe(|| {
let raw = arena.alloc_slice_shared_with_or_panic::<u8, _>(u16::MAX as usize + 1, None, |_, slot| {
slot.write(0);
});
let _arc: crate::Arc<[u8], Global> = unsafe { crate::Arc::from_value_ptr(raw) };
}));
assert!(res.is_ok(), "no drop_fn ⇒ no u16::MAX cap, must not panic");
}
#[cfg(feature = "std")]
#[test]
fn try_alloc_slice_local_oversized_with_partial_init_drops_partial() {
use core::cell::Cell;
use std::panic::AssertUnwindSafe;
struct D<'a>(&'a Cell<u32>);
impl Drop for D<'_> {
fn drop(&mut self) {
self.0.set(self.0.get() + 1);
}
}
let drops = Cell::new(0_u32);
let arena = Arena::<Global>::builder().max_normal_alloc(4096).build();
let res = std::panic::catch_unwind(AssertUnwindSafe(|| {
arena.try_alloc_slice_local_oversized_with::<D<'_>, _>(64, AllocFlavor::Rc, Some(drop_shim_one::<D<'_>>), |i, slot| {
assert!(i != 17, "synthetic init panic at i=17");
slot.write(D(&drops));
})
}));
assert!(res.is_err());
assert_eq!(drops.get(), 17, "exactly the 17 successfully-written elements must drop");
}
#[cfg(feature = "std")]
#[test]
fn try_alloc_slice_shared_oversized_with_partial_init_drops_partial() {
use std::panic::AssertUnwindSafe;
use std::sync::Mutex;
struct D(&'static Mutex<u32>);
impl Drop for D {
fn drop(&mut self) {
let mut g = self.0.lock().unwrap();
*g += 1;
}
}
static DROPS: Mutex<u32> = Mutex::new(0);
let baseline = *DROPS.lock().unwrap();
let arena = Arena::<Global>::builder().max_normal_alloc(4096).build();
let res = std::panic::catch_unwind(AssertUnwindSafe(|| {
arena.try_alloc_slice_shared_oversized_with::<D, _>(64, Some(drop_shim_one::<D>), |i, slot| {
assert!(i != 17, "synthetic init panic at i=17");
slot.write(D(&DROPS));
})
}));
assert!(res.is_err());
assert_eq!(
*DROPS.lock().unwrap() - baseline,
17,
"exactly the 17 successfully-written elements must drop"
);
}
#[test]
fn try_alloc_slice_shared_oversized_with_small_len_drop_fn_succeeds() {
let arena = Arena::<Global>::builder().max_normal_alloc(4096).build();
let raw = arena.try_alloc_slice_shared_oversized_with::<u32, _>(100, Some(noop_drop_shim), |_, slot| {
slot.write(0);
});
assert!(raw.is_ok(), "len=100 with drop_fn must not be rejected");
let _arc: crate::Arc<[u32], Global> = unsafe { crate::Arc::from_value_ptr(raw.unwrap()) };
}
#[test]
fn alloc_with_drop_runs_destructor_on_arena_drop() {
use core::cell::Cell;
struct D<'a>(&'a Cell<u32>);
impl Drop for D<'_> {
fn drop(&mut self) {
self.0.set(self.0.get() + 1);
}
}
let drops = Cell::new(0_u32);
let arena = Arena::<Global>::new();
let _r: &mut D<'_> = arena.alloc_with(|| D(&drops));
assert_eq!(drops.get(), 0, "drop must not run before arena is dropped");
drop(arena);
assert_eq!(drops.get(), 1, "drop must run exactly once when arena is dropped");
}
#[cfg(feature = "stats")]
#[test]
fn try_alloc_uninit_slice_at_max_normal_uses_fast_path() {
let arena = Arena::<Global>::builder()
.max_normal_alloc(MIN_MAX_NORMAL_ALLOC)
.with_capacity_local(64 * 1024)
.build();
let _ = arena.alloc::<u8>(0);
let before = arena.stats().normal_local_chunks_allocated;
let _ = arena
.try_alloc_slice_fill_with::<u64, _>(MIN_MAX_NORMAL_ALLOC / 8, |_| 0)
.expect("must fit");
let after = arena.stats().normal_local_chunks_allocated;
assert_eq!(before, after, "exact max_normal_alloc must not need a new chunk");
}
#[cfg(feature = "stats")]
#[test]
fn try_alloc_slice_copy_at_max_normal_uses_fast_path() {
let arena = Arena::<Global>::builder()
.max_normal_alloc(MIN_MAX_NORMAL_ALLOC)
.with_capacity_local(64 * 1024)
.build();
let _ = arena.alloc::<u8>(0);
let src: alloc::vec::Vec<u64> = alloc::vec![0_u64; MIN_MAX_NORMAL_ALLOC / 8];
let before = arena.stats().normal_local_chunks_allocated;
let _ = arena.try_alloc_slice_copy(&*src).expect("must fit");
let after = arena.stats().normal_local_chunks_allocated;
assert_eq!(before, after, "exact max_normal_alloc must not need a new chunk");
}
#[cfg(feature = "stats")]
#[test]
fn alloc_slice_copy_at_max_normal_uses_fast_path() {
let arena = Arena::<Global>::builder()
.max_normal_alloc(MIN_MAX_NORMAL_ALLOC)
.with_capacity_local(64 * 1024)
.build();
let _ = arena.alloc::<u8>(0);
let src: alloc::vec::Vec<u64> = alloc::vec![0_u64; MIN_MAX_NORMAL_ALLOC / 8];
let before = arena.stats().normal_local_chunks_allocated;
let _ = arena.alloc_slice_copy(&*src);
let after = arena.stats().normal_local_chunks_allocated;
assert_eq!(before, after, "exact max_normal_alloc must not need a new chunk");
}
#[cfg(feature = "stats")]
#[test]
fn try_alloc_slice_copy_arc_at_max_normal_uses_fast_path() {
let arena = Arena::<Global>::builder()
.max_normal_alloc(MIN_MAX_NORMAL_ALLOC)
.with_capacity_shared(64 * 1024)
.build();
let _ = arena.alloc_arc::<u8>(0);
let src: alloc::vec::Vec<u64> = alloc::vec![0_u64; MIN_MAX_NORMAL_ALLOC / 8];
let before = arena.stats().normal_shared_chunks_allocated;
let _ = arena.try_alloc_slice_copy_arc(&*src).expect("must fit");
let after = arena.stats().normal_shared_chunks_allocated;
assert_eq!(before, after, "exact max_normal_alloc must not need a new chunk");
}
#[cfg(feature = "stats")]
#[test]
fn try_alloc_uninit_slice_arc_at_max_normal_uses_fast_path() {
let arena = Arena::<Global>::builder()
.max_normal_alloc(MIN_MAX_NORMAL_ALLOC)
.with_capacity_shared(64 * 1024)
.build();
let _ = arena.alloc_arc::<u8>(0);
let before = arena.stats().normal_shared_chunks_allocated;
let _ = arena
.try_alloc_slice_fill_with_arc::<u64, _>(MIN_MAX_NORMAL_ALLOC / 8, |_| 0)
.expect("must fit");
let after = arena.stats().normal_shared_chunks_allocated;
assert_eq!(before, after, "exact max_normal_alloc must not need a new chunk");
}
#[cfg(feature = "stats")]
#[test]
fn try_alloc_uninit_slice_slow_at_max_normal_refills() {
let arena = Arena::<Global>::builder()
.max_normal_alloc(MIN_MAX_NORMAL_ALLOC)
.with_capacity_local(MIN_MAX_NORMAL_ALLOC)
.build();
let _ = arena.alloc::<u8>(0);
let before = arena.stats().wasted_tail_bytes;
let _ = arena
.try_alloc_slice_fill_with::<u64, _>(MIN_MAX_NORMAL_ALLOC / 8, |_| 0)
.expect("slow-path refill must succeed");
let after = arena.stats().wasted_tail_bytes;
assert!(
after > before,
"slow path at exactly max_normal_alloc must refill_local (charges wasted tail); the `>=` mutant would route to the oversized helper instead",
);
}
#[cfg(feature = "stats")]
#[test]
fn try_alloc_slice_copy_slow_at_max_normal_refills() {
let arena = Arena::<Global>::builder()
.max_normal_alloc(MIN_MAX_NORMAL_ALLOC)
.with_capacity_local(MIN_MAX_NORMAL_ALLOC)
.build();
let _ = arena.alloc::<u8>(0);
let src: alloc::vec::Vec<u64> = alloc::vec![0_u64; MIN_MAX_NORMAL_ALLOC / 8];
let before = arena.stats().wasted_tail_bytes;
let _ = arena.try_alloc_slice_copy(&*src).expect("slow-path refill must succeed");
let after = arena.stats().wasted_tail_bytes;
assert!(
after > before,
"slow path at exactly max_normal_alloc must refill_local (charges wasted tail); the `>=` mutant would route to the oversized helper instead",
);
}
#[cfg(feature = "stats")]
#[test]
fn try_alloc_slice_copy_arc_slow_at_max_normal_refills() {
let arena = Arena::<Global>::builder()
.max_normal_alloc(MIN_MAX_NORMAL_ALLOC)
.with_capacity_shared(MIN_MAX_NORMAL_ALLOC)
.build();
let _ = arena.alloc_arc::<u8>(0);
let src: alloc::vec::Vec<u64> = alloc::vec![0_u64; MIN_MAX_NORMAL_ALLOC / 8];
let before = arena.stats().wasted_tail_bytes;
let _ = arena.try_alloc_slice_copy_arc(&*src).expect("slow-path refill must succeed");
let after = arena.stats().wasted_tail_bytes;
assert!(
after > before,
"slow path at exactly max_normal_alloc must refill_shared (charges wasted tail); the `>=` mutant would route to the oversized helper instead",
);
}
#[cfg(feature = "stats")]
#[test]
fn allocate_layout_slow_at_max_normal_refills() {
use core::alloc::Layout;
use allocator_api2::alloc::Allocator;
let arena = Arena::<Global>::builder()
.max_normal_alloc(MIN_MAX_NORMAL_ALLOC)
.with_capacity_local(MIN_MAX_NORMAL_ALLOC)
.build();
let _ = arena.alloc::<u8>(0);
let before = arena.stats().wasted_tail_bytes;
let layout = Layout::from_size_align(MIN_MAX_NORMAL_ALLOC, 8).expect("valid layout");
let ptr = (&arena).allocate(layout).expect("slow-path refill must succeed");
let after = arena.stats().wasted_tail_bytes;
unsafe { (&arena).deallocate(ptr.cast::<u8>(), layout) };
assert!(
after > before,
"slow path at exactly max_normal_alloc must refill_local (charges wasted tail); the `>=` mutant would route to allocate_oversized_layout instead",
);
}
#[test]
fn allocate_layout_slow_high_align_does_not_underflow_needed() {
use core::alloc::Layout;
use allocator_api2::alloc::Allocator;
let arena = Arena::<Global>::new();
let align = (core::mem::align_of::<usize>() * 2).max(16);
let layout = Layout::from_size_align(1, align).expect("valid layout");
let ptr = (&arena)
.allocate(layout)
.expect("small high-align allocation must succeed; the `+ -> -` mutant underflows `needed` and rejects the refill");
assert!(!ptr.is_empty(), "allocator must return a non-empty slot");
unsafe { (&arena).deallocate(ptr.cast::<u8>(), layout) };
}
#[cfg(all(feature = "stats", any(feature = "dst", feature = "bytesbuf")))]
#[test]
fn allocate_shared_layout_slow_at_max_normal_refills() {
use core::alloc::Layout;
use crate::internal::in_chunk::InSharedChunk;
use crate::internal::shared_chunk::SharedChunk;
let arena = Arena::<Global>::builder()
.max_normal_alloc(MIN_MAX_NORMAL_ALLOC)
.with_capacity_shared(MIN_MAX_NORMAL_ALLOC)
.build();
let _ = arena.alloc_arc::<u8>(0);
let before = arena.stats().wasted_tail_bytes;
let layout = Layout::from_size_align(MIN_MAX_NORMAL_ALLOC, 8).expect("valid layout");
let raw = arena.allocate_shared_layout(layout).expect("slow-path refill must succeed");
let after = arena.stats().wasted_tail_bytes;
let chunk = unsafe { InSharedChunk::<u8, Global>::new(raw) }.chunk_ptr();
unsafe { SharedChunk::dec_ref(chunk) };
assert!(
after > before,
"slow path at exactly max_normal_alloc must refill_shared (charges wasted tail); the `>=` mutant would route to allocate_shared_oversized_layout instead",
);
}
#[cfg(feature = "std")]
#[test]
fn alloc_arc_no_drop_after_drop_does_not_clobber_prior_entry() {
use std::sync::Mutex;
struct DropType(&'static Mutex<u32>);
impl Drop for DropType {
fn drop(&mut self) {
*self.0.lock().unwrap() += 1;
}
}
static DROPS: Mutex<u32> = Mutex::new(0);
let baseline = *DROPS.lock().unwrap();
let arena = Arena::<Global>::default();
let a1 = arena.alloc_arc::<DropType>(DropType(&DROPS));
let a2 = arena.alloc_arc::<u32>(0xdead_beef);
drop(a1);
drop(a2);
drop(arena);
assert_eq!(
*DROPS.lock().unwrap() - baseline,
1,
"DropType's drop must run exactly once even after a no-drop arc allocates after it"
);
}
#[cfg(feature = "std")]
#[test]
fn alloc_with_no_drop_after_drop_does_not_clobber_prior_entry() {
use std::sync::Mutex;
struct DropType<'a>(&'a Mutex<u32>);
impl Drop for DropType<'_> {
fn drop(&mut self) {
*self.0.lock().unwrap() += 1;
}
}
static DROPS: Mutex<u32> = Mutex::new(0);
let baseline = *DROPS.lock().unwrap();
let arena = Arena::<Global>::default();
let _r1 = arena.alloc_with(|| DropType(&DROPS));
let _r2 = arena.alloc_with(|| 0xdead_beef_u32);
drop(arena);
assert_eq!(
*DROPS.lock().unwrap() - baseline,
1,
"DropType's drop must run exactly once even after a no-drop alloc_with follows it"
);
}
#[cfg(feature = "std")]
#[test]
fn alloc_slice_local_with_rc_flavor_drops_run() {
use std::cell::Cell;
struct D<'a>(&'a Cell<u32>);
impl Drop for D<'_> {
fn drop(&mut self) {
self.0.set(self.0.get() + 1);
}
}
let drops = Cell::new(0_u32);
let arena = Arena::<Global>::default();
let _ = arena.alloc_slice_local_with_or_panic::<D<'_>, _>(4, AllocFlavor::SimpleRef, Some(drop_shim_slice::<D<'_>>), |_, slot| {
slot.write(D(&drops));
});
drop(arena);
assert_eq!(drops.get(), 4, "all 4 D elements must be dropped via replay_drops");
}
#[cfg(feature = "std")]
#[test]
fn alloc_slice_shared_with_drops_run() {
use std::sync::Mutex;
struct D(&'static Mutex<u32>);
impl Drop for D {
fn drop(&mut self) {
*self.0.lock().unwrap() += 1;
}
}
static DROPS: Mutex<u32> = Mutex::new(0);
let baseline = *DROPS.lock().unwrap();
let arena = Arena::<Global>::default();
let raw = arena.alloc_slice_shared_with_or_panic::<D, _>(4, Some(drop_shim_slice::<D>), |_, slot| {
slot.write(D(&DROPS));
});
let arc: crate::Arc<[D], Global> = unsafe { crate::Arc::from_value_ptr(raw) };
drop(arc);
drop(arena);
assert_eq!(
*DROPS.lock().unwrap() - baseline,
4,
"all 4 D elements must be dropped via replay_drops on the shared chunk"
);
}
#[test]
fn try_alloc_slice_local_oversized_with_drop_fn_too_long_returns_err() {
let arena = Arena::<Global>::new();
let res =
arena.try_alloc_slice_local_oversized_with::<u8, _>(u16::MAX as usize + 1, AllocFlavor::Rc, Some(noop_drop_shim), |_, slot| {
slot.write(0);
});
assert!(res.is_err());
}
#[test]
fn try_alloc_slice_shared_oversized_with_drop_fn_too_long_returns_err() {
let arena = Arena::<Global>::new();
let res = arena.try_alloc_slice_shared_oversized_with::<u8, _>(u16::MAX as usize + 1, Some(noop_drop_shim), |_, slot| {
slot.write(0);
});
assert!(res.is_err());
}
#[cfg(feature = "std")]
#[test]
#[should_panic(expected = "multitude: allocator returned AllocError")]
fn alloc_slice_local_with_or_panic_layout_overflow_panics() {
let arena = Arena::<Global>::new();
let len = usize::MAX / core::mem::size_of::<u64>() + 1;
let _ = arena.alloc_slice_local_with_or_panic::<u64, _>(len, AllocFlavor::SimpleRef, None, |_, slot| {
slot.write(0);
});
}
#[cfg(feature = "std")]
#[test]
#[should_panic(expected = "multitude: allocator returned AllocError")]
fn alloc_slice_local_with_or_panic_over_aligned_panics() {
#[repr(align(32768))]
struct HugeAlign(#[allow(dead_code, reason = "field forces alignment")] u8);
let arena = Arena::<Global>::new();
let _ = arena.alloc_slice_local_with_or_panic::<HugeAlign, _>(1, AllocFlavor::SimpleRef, None, |_, slot| {
slot.write(HugeAlign(0));
});
}
#[cfg(feature = "std")]
#[test]
#[should_panic(expected = "multitude: allocator returned AllocError")]
fn alloc_slice_local_with_or_panic_drop_fn_too_long_panics() {
let arena = Arena::<Global>::new();
let _ =
arena.alloc_slice_local_with_or_panic::<u8, _>(u16::MAX as usize + 1, AllocFlavor::SimpleRef, Some(noop_drop_shim), |_, slot| {
slot.write(0);
});
}
#[cfg(feature = "std")]
#[test]
#[should_panic(expected = "multitude: allocator returned AllocError")]
fn alloc_slice_local_with_or_panic_refill_failure_panics() {
use core::cell::Cell;
use allocator_api2::alloc::{AllocError, Allocator, Layout};
#[derive(Clone)]
struct FailEverything;
unsafe impl Allocator for FailEverything {
fn allocate(&self, _layout: Layout) -> Result<core::ptr::NonNull<[u8]>, AllocError> {
Err(AllocError)
}
unsafe fn deallocate(&self, _ptr: core::ptr::NonNull<u8>, _layout: Layout) {}
}
let _ = Cell::new(0); let arena = crate::ArenaBuilder::new_in(FailEverything).build();
let _ = arena.alloc_slice_local_with_or_panic::<u8, _>(64, AllocFlavor::SimpleRef, None, |_, slot| {
slot.write(0);
});
}
#[repr(align(32768))]
struct HugeAlign32K(#[expect(dead_code, reason = "alignment marker")] u8);
#[repr(align(65536))]
struct HugeAlign64K(#[expect(dead_code, reason = "alignment marker")] u8);
#[derive(Clone, Copy)]
struct FailEverythingAllocator;
unsafe impl allocator_api2::alloc::Allocator for FailEverythingAllocator {
fn allocate(&self, _layout: core::alloc::Layout) -> Result<core::ptr::NonNull<[u8]>, allocator_api2::alloc::AllocError> {
Err(allocator_api2::alloc::AllocError)
}
unsafe fn deallocate(&self, _ptr: core::ptr::NonNull<u8>, _layout: core::alloc::Layout) {}
}
const HUGE_LEN: usize = usize::MAX / 2;
#[test]
fn try_alloc_slice_local_oversized_with_layout_overflow_returns_err() {
let arena = Arena::<Global>::new();
let res = arena.try_alloc_slice_local_oversized_with::<u64, _>(HUGE_LEN, AllocFlavor::SimpleRef, None, |_, slot| {
slot.write(0);
});
assert!(res.is_err());
}
#[test]
fn try_alloc_slice_shared_oversized_with_layout_overflow_returns_err() {
let arena = Arena::<Global>::new();
let res = arena.try_alloc_slice_shared_oversized_with::<u64, _>(HUGE_LEN, None, |_, slot| {
slot.write(0);
});
assert!(res.is_err());
}
#[test]
fn try_alloc_slice_with_layout_overflow_returns_err() {
let arena = Arena::<Global>::new();
let res = arena.try_alloc_slice_fill_with::<u64, _>(HUGE_LEN, |i| i as u64);
assert!(res.is_err());
}
#[test]
fn try_alloc_slice_fill_with_over_aligned_returns_err() {
let arena = Arena::<Global>::new();
let res = arena.try_alloc_slice_fill_with_box::<HugeAlign32K, _>(1, |_| HugeAlign32K(0));
assert!(res.is_err());
}
#[test]
#[should_panic(expected = "multitude: allocator returned AllocError")]
fn alloc_slice_shared_with_or_panic_layout_overflow_panics() {
let arena = Arena::<Global>::new();
let _ = arena.alloc_slice_shared_with_or_panic::<u64, _>(HUGE_LEN, None, |_, slot| {
slot.write(0);
});
}
#[test]
#[should_panic(expected = "multitude: allocator returned AllocError")]
fn alloc_slice_shared_with_or_panic_over_aligned_panics() {
let arena = Arena::<Global>::new();
let _ = arena.alloc_slice_shared_with_or_panic::<HugeAlign32K, _>(1, None, |_, slot| {
slot.write(HugeAlign32K(0));
});
}
#[test]
#[should_panic(expected = "multitude: allocator returned AllocError")]
fn alloc_slice_shared_with_or_panic_drop_fn_too_long_panics() {
let arena = Arena::<Global>::new();
let _ = arena.alloc_slice_shared_with_or_panic::<u8, _>(u16::MAX as usize + 1, Some(noop_drop_shim), |_, slot| {
slot.write(0);
});
}
#[test]
#[should_panic(expected = "multitude: allocator returned AllocError")]
fn alloc_slice_shared_with_or_panic_refill_failure_panics() {
let arena = crate::ArenaBuilder::new_in(FailEverythingAllocator).build();
let _ = arena.alloc_slice_shared_with_or_panic::<u8, _>(64, None, |_, slot| {
slot.write(0);
});
}
#[test]
fn try_alloc_slice_copy_layout_overflow_returns_err() {
let arena = Arena::<Global>::new();
let res = arena.try_alloc_slice_local_no_drop_with::<u64, _, false>(HUGE_LEN, AllocFlavor::SimpleRef, |_, slot| {
slot.write(0);
});
assert!(res.is_err());
}
#[test]
fn try_alloc_slice_local_no_drop_with_over_aligned_returns_err_box_flavor() {
let arena = Arena::<Global>::new();
let res = arena.try_alloc_slice_local_no_drop_with::<HugeAlign32K, _, false>(1, AllocFlavor::Box, |_, slot| {
slot.write(HugeAlign32K(0));
});
assert!(res.is_err());
}
#[test]
fn try_alloc_slice_local_no_drop_with_over_aligned_returns_err_simpleref_flavor() {
let arena = Arena::<Global>::new();
let res = arena.try_alloc_slice_local_no_drop_with::<HugeAlign64K, _, false>(1, AllocFlavor::SimpleRef, |_, slot| {
slot.write(HugeAlign64K(0));
});
assert!(res.is_err());
}
#[test]
fn try_alloc_slice_shared_no_drop_with_layout_overflow_returns_err() {
let arena = Arena::<Global>::new();
let res = arena.try_alloc_slice_shared_no_drop_with::<u64, _, false>(HUGE_LEN, |_, slot| {
slot.write(0);
});
assert!(res.is_err());
}
#[test]
fn try_alloc_slice_shared_no_drop_with_over_aligned_returns_err() {
let arena = Arena::<Global>::new();
let res = arena.try_alloc_slice_shared_no_drop_with::<HugeAlign32K, _, false>(1, |_, slot| {
slot.write(HugeAlign32K(0));
});
assert!(res.is_err());
}
#[test]
fn try_alloc_slice_shared_copy_layout_overflow_returns_err() {
let arena = Arena::<Global>::new();
let res = arena.try_alloc_slice_copy_arc::<u64>(&[1, 2, 3]);
assert!(res.is_ok(), "sanity check for normal path");
}
#[test]
#[should_panic(expected = "multitude: allocator returned AllocError")]
fn alloc_slice_fill_with_box_layout_overflow_panics() {
let arena = Arena::<Global>::new();
let _ = arena.alloc_slice_fill_with_box::<u64, _>(HUGE_LEN, |i| i as u64);
}
#[test]
#[should_panic(expected = "multitude: allocator returned AllocError")]
fn alloc_slice_fill_with_layout_overflow_panics() {
let arena = Arena::<Global>::new();
let _ = arena.alloc_slice_fill_with::<u64, _>(HUGE_LEN, |i| i as u64);
}
#[test]
#[should_panic(expected = "multitude: allocator returned AllocError")]
fn alloc_slice_fill_with_box_over_aligned_panics() {
let arena = Arena::<Global>::new();
let _ = arena.alloc_slice_fill_with_box::<HugeAlign32K, _>(1, |_| HugeAlign32K(0));
}
unsafe impl Send for HugeAlign32K {}
unsafe impl Sync for HugeAlign32K {}
#[test]
#[should_panic(expected = "multitude: allocator returned AllocError")]
fn alloc_slice_fill_with_arc_layout_overflow_panics() {
let arena = Arena::<Global>::new();
let _ = arena.alloc_slice_fill_with_arc::<u64, _>(HUGE_LEN, |i| i as u64);
}
#[test]
#[should_panic(expected = "multitude: allocator returned AllocError")]
fn alloc_slice_fill_with_arc_over_aligned_panics() {
let arena = Arena::<Global>::new();
let _ = arena.alloc_slice_fill_with_arc::<HugeAlign32K, _>(1, |_| HugeAlign32K(0));
}
#[cfg(not(target_os = "windows"))]
#[repr(align(65536))]
#[derive(Clone, Copy)]
struct HugeAlign64KCopy(#[expect(dead_code, reason = "alignment marker")] u8);
#[cfg(not(target_os = "windows"))]
unsafe impl Send for HugeAlign64KCopy {}
#[cfg(not(target_os = "windows"))]
unsafe impl Sync for HugeAlign64KCopy {}
#[test]
#[cfg(not(target_os = "windows"))]
#[should_panic(expected = "multitude: allocator returned AllocError")]
fn alloc_slice_copy_arc_over_aligned_panics() {
let arena = Arena::<Global>::new();
let v: alloc::vec::Vec<HugeAlign64KCopy> = alloc::vec::Vec::new();
let _ = arena.alloc_slice_copy_arc::<HugeAlign64KCopy>(&*v);
}
#[cfg(feature = "dst")]
#[test]
fn try_alloc_dst_rc_oversized_metadata_returns_err() {
use core::alloc::Layout;
let arena = Arena::<Global>::new();
let len = u16::MAX as usize + 1;
let layout = Layout::array::<u8>(len).unwrap();
let res = unsafe {
arena.try_alloc_dst_rc::<[u8]>(layout, len, |fat: *mut [u8]| {
let p = fat.cast::<u8>();
for i in 0..len {
p.add(i).write(0);
}
})
};
assert!(res.is_err());
}
#[cfg(feature = "dst")]
#[test]
fn try_alloc_dst_arc_oversized_metadata_returns_err() {
use core::alloc::Layout;
let arena = Arena::<Global>::new();
let len = u16::MAX as usize + 1;
let layout = Layout::array::<u8>(len).unwrap();
let res = unsafe {
arena.try_alloc_dst_arc::<[u8]>(layout, len, |fat: *mut [u8]| {
let p = fat.cast::<u8>();
for i in 0..len {
p.add(i).write(0);
}
})
};
assert!(res.is_err());
}
#[cfg(feature = "dst")]
#[test]
fn try_alloc_dst_box_oversized_metadata_drop_aware_returns_err() {
use core::alloc::Layout;
struct DropProbe;
impl Drop for DropProbe {
fn drop(&mut self) {}
}
let arena = Arena::<Global>::new();
let len = u16::MAX as usize + 1;
let layout = Layout::array::<DropProbe>(len).unwrap();
let res = unsafe {
arena.try_alloc_dst_box::<[DropProbe]>(layout, len, |fat: *mut [DropProbe]| {
let p = fat.cast::<DropProbe>();
for i in 0..len {
p.add(i).write(DropProbe);
}
})
};
assert!(res.is_err());
}
#[cfg(feature = "dst")]
#[test]
fn try_alloc_dst_arc_over_aligned_returns_err() {
use core::alloc::Layout;
let arena = Arena::<Global>::new();
let layout = Layout::from_size_align(32_768, 32_768).unwrap();
let res = unsafe { arena.try_alloc_dst_arc::<[u8]>(layout, 32_768, |_| {}) };
assert!(res.is_err());
}
#[cfg(feature = "dst")]
#[test]
fn try_alloc_dst_rc_over_aligned_returns_err() {
use core::alloc::Layout;
let arena = Arena::<Global>::new();
let layout = Layout::from_size_align(32_768, 32_768).unwrap();
let res = unsafe { arena.try_alloc_dst_rc::<[u8]>(layout, 32_768, |_| {}) };
assert!(res.is_err());
}
#[cfg(feature = "dst")]
#[test]
fn try_alloc_dst_box_over_aligned_returns_err() {
use core::alloc::Layout;
let arena = Arena::<Global>::new();
let layout = Layout::from_size_align(32_768, 32_768).unwrap();
let res = unsafe { arena.try_alloc_dst_box::<[u8]>(layout, 32_768, |_| {}) };
assert!(res.is_err());
}
#[cfg(feature = "dst")]
#[test]
fn try_alloc_dst_arc_refill_failure_returns_err() {
use core::alloc::Layout;
let arena = crate::ArenaBuilder::new_in(FailEverythingAllocator).build();
let layout = Layout::array::<u8>(64).unwrap();
let res = unsafe { arena.try_alloc_dst_arc::<[u8]>(layout, 64, |_| {}) };
assert!(res.is_err());
}
#[cfg(feature = "dst")]
#[test]
fn try_alloc_dst_rc_refill_failure_returns_err() {
use core::alloc::Layout;
let arena = crate::ArenaBuilder::new_in(FailEverythingAllocator).build();
let layout = Layout::array::<u8>(64).unwrap();
let res = unsafe { arena.try_alloc_dst_rc::<[u8]>(layout, 64, |_| {}) };
assert!(res.is_err());
}
#[cfg(feature = "dst")]
#[test]
fn try_alloc_dst_box_refill_failure_returns_err() {
use core::alloc::Layout;
let arena = crate::ArenaBuilder::new_in(FailEverythingAllocator).build();
let layout = Layout::array::<u8>(64).unwrap();
let res = unsafe { arena.try_alloc_dst_box::<[u8]>(layout, 64, |_| {}) };
assert!(res.is_err());
}
#[derive(Clone)]
struct DropProbe(#[expect(dead_code, reason = "drop probe payload")] u64);
impl Drop for DropProbe {
fn drop(&mut self) {}
}
#[test]
fn try_alloc_slice_fill_with_box_drop_layout_overflow_returns_err() {
let arena = Arena::<Global>::new();
let res = arena.try_alloc_slice_fill_with_box::<DropProbe, _>(HUGE_LEN, |_| DropProbe(0));
assert!(res.is_err());
}
#[test]
fn try_alloc_slice_fill_with_box_drop_too_long_returns_err() {
let arena = Arena::<Global>::new();
let res = arena.try_alloc_slice_fill_with_box::<DropProbe, _>(u16::MAX as usize + 1, |_| DropProbe(0));
assert!(res.is_err());
}
#[test]
fn try_alloc_slice_fill_with_arc_drop_layout_overflow_returns_err() {
let arena = Arena::<Global>::new();
#[derive(Clone)]
struct SendDropProbe(#[expect(dead_code, reason = "drop probe payload")] u64);
impl Drop for SendDropProbe {
fn drop(&mut self) {}
}
let res = arena.try_alloc_slice_fill_with_arc::<SendDropProbe, _>(HUGE_LEN, |_| SendDropProbe(0));
assert!(res.is_err());
}
#[test]
fn try_alloc_slice_fill_with_arc_drop_too_long_returns_err() {
let arena = Arena::<Global>::new();
#[derive(Clone)]
struct SendDropProbe(#[expect(dead_code, reason = "drop probe payload")] u64);
impl Drop for SendDropProbe {
fn drop(&mut self) {}
}
let res = arena.try_alloc_slice_fill_with_arc::<SendDropProbe, _>(u16::MAX as usize + 1, |_| SendDropProbe(0));
assert!(res.is_err());
}
#[test]
fn try_alloc_slice_copy_layout_overflow_via_public_returns_err() {
let arena = Arena::<Global>::new();
let res = arena.try_alloc_slice_copy(&[1u64, 2, 3]);
assert!(res.is_ok());
}
#[test]
fn try_alloc_slice_copy_at_max_normal_sanity() {
let arena = Arena::<Global>::new();
let res = arena.try_alloc_slice_copy::<u8>(&[1, 2, 3]);
assert!(res.is_ok());
}
type OversizedBlob = [u8; 128 * 1024];
#[test]
fn try_alloc_with_oversized_refill_failure_returns_err() {
let arena = crate::ArenaBuilder::new_in(FailEverythingAllocator).build();
let res = arena.try_alloc_with::<OversizedBlob, _>(|| [0u8; 128 * 1024]);
assert!(res.is_err());
}
#[test]
fn try_alloc_oversized_refill_failure_returns_err() {
let arena = crate::ArenaBuilder::new_in(FailEverythingAllocator).build();
let res = arena.try_alloc::<OversizedBlob>([0u8; 128 * 1024]);
assert!(res.is_err());
}
#[test]
fn try_alloc_arc_oversized_refill_failure_returns_err() {
let arena = crate::ArenaBuilder::new_in(FailEverythingAllocator).build();
let res = arena.try_alloc_arc::<OversizedBlob>([0u8; 128 * 1024]);
assert!(res.is_err());
}
#[cfg(feature = "dst")]
#[test]
fn try_alloc_dst_arc_oversized_refill_failure_returns_err() {
use core::alloc::Layout;
#[derive(Clone)]
struct SendDropProbe(#[expect(dead_code, reason = "padding")] u64);
impl Drop for SendDropProbe {
fn drop(&mut self) {}
}
let arena = crate::ArenaBuilder::new_in(FailEverythingAllocator).build();
let layout = Layout::array::<SendDropProbe>(16384).unwrap();
let res = unsafe { arena.try_alloc_dst_arc::<[SendDropProbe]>(layout, 16384, |_| {}) };
assert!(res.is_err());
}
#[cfg(feature = "dst")]
#[test]
fn try_alloc_dst_box_oversized_refill_failure_returns_err() {
use core::alloc::Layout;
struct DropProbe(#[expect(dead_code, reason = "padding")] u64);
impl Drop for DropProbe {
fn drop(&mut self) {}
}
let arena = crate::ArenaBuilder::new_in(FailEverythingAllocator).build();
let layout = Layout::array::<DropProbe>(16384).unwrap();
let res = unsafe { arena.try_alloc_dst_box::<[DropProbe]>(layout, 16384, |_| {}) };
assert!(res.is_err());
}
#[cfg(feature = "dst")]
#[test]
fn try_alloc_dst_rc_oversized_refill_failure_returns_err() {
use core::alloc::Layout;
struct DropProbe(#[expect(dead_code, reason = "padding")] u64);
impl Drop for DropProbe {
fn drop(&mut self) {}
}
let arena = crate::ArenaBuilder::new_in(FailEverythingAllocator).build();
let layout = Layout::array::<DropProbe>(16384).unwrap();
let res = unsafe { arena.try_alloc_dst_rc::<[DropProbe]>(layout, 16384, |_| {}) };
assert!(res.is_err());
}
#[cfg(feature = "dst")]
#[test]
fn align_up_identity_when_already_aligned() {
assert_eq!(align_up(0, 4), 0);
assert_eq!(align_up(0, 8), 0);
assert_eq!(align_up(4, 4), 4);
assert_eq!(align_up(8, 8), 8);
}
#[cfg(feature = "dst")]
#[test]
fn align_up_rounds_up_to_alignment() {
assert_eq!(align_up(1, 4), 4);
assert_eq!(align_up(5, 4), 8);
assert_eq!(align_up(7, 4), 8);
assert_eq!(align_up(9, 8), 16);
}
#[cfg(feature = "dst")]
#[test]
fn align_up_align_one_is_identity() {
assert_eq!(align_up(0, 1), 0);
assert_eq!(align_up(1, 1), 1);
assert_eq!(align_up(42, 1), 42);
}