use core::mem;
use core::sync::atomic::{AtomicPtr, Ordering};
#[inline]
pub(crate) const fn round_payload(min_payload: usize, header_size: usize) -> Option<usize> {
let entry_align = mem::align_of::<DropEntry>();
let mask = entry_align - 1;
let Some(total) = header_size.checked_add(min_payload) else {
return None;
};
let Some(rounded_total) = total.checked_add(mask) else {
return None;
};
Some((rounded_total & !mask) - header_size)
}
#[repr(C)]
pub(crate) struct DropEntry {
pub(crate) drop_fn: AtomicPtr<()>,
pub(crate) value_offset: u16,
pub(crate) len: u16,
_pad: [u8; PAD_BYTES],
}
const PAD_TARGET: usize = mem::align_of::<unsafe fn(*mut u8, usize)>();
#[cfg_attr(test, mutants::skip)] #[cfg_attr(coverage_nightly, coverage(off))]
const fn raw_used() -> usize {
mem::size_of::<unsafe fn(*mut u8, usize)>() + 2 + 2
}
#[cfg_attr(test, mutants::skip)] #[cfg_attr(coverage_nightly, coverage(off))]
const fn pad_bytes() -> usize {
let raw = raw_used();
if raw.is_multiple_of(PAD_TARGET) {
0
} else {
PAD_TARGET - (raw % PAD_TARGET)
}
}
const PAD_BYTES: usize = pad_bytes();
impl DropEntry {
#[inline]
pub(crate) const fn new(drop_fn: unsafe fn(*mut u8, usize), value_offset: u16, len: u16) -> Self {
Self {
#[expect(
clippy::fn_to_numeric_cast_any,
reason = "fn-ptr storage in AtomicPtr is the type-erased shim location"
)]
drop_fn: AtomicPtr::new(drop_fn as *mut ()),
value_offset,
len,
_pad: [0; PAD_BYTES],
}
}
#[inline]
#[expect(
clippy::fn_to_numeric_cast_any,
reason = "fn-ptr storage in AtomicPtr is the type-erased shim location"
)]
pub(crate) fn store_drop_fn(&self, drop_fn: unsafe fn(*mut u8, usize), order: Ordering) {
self.drop_fn.store(drop_fn as *mut (), order);
}
#[inline]
pub(crate) fn load_drop_fn(&self, order: Ordering) -> unsafe fn(*mut u8, usize) {
let p = self.drop_fn.load(order);
unsafe { mem::transmute::<*mut (), unsafe fn(*mut u8, usize)>(p) }
}
#[inline]
pub(crate) unsafe fn write_at_offset(self, data_ptr: core::ptr::NonNull<u8>, byte_offset: usize) {
#[expect(
clippy::cast_ptr_alignment,
reason = "back-stack slots are placed at naturally-aligned addresses by the bump allocator (CHUNK_ALIGN >= align_of::<DropEntry>())"
)]
unsafe {
let entry_ptr = data_ptr.as_ptr().add(byte_offset).cast::<Self>();
core::ptr::write(entry_ptr, self);
}
}
}
pub(crate) unsafe fn noop_drop_shim(_value: *mut u8, _len: usize) {}
pub(crate) unsafe fn drop_shim_one<T>(value: *mut u8, len: usize) {
debug_assert_eq!(len, 1, "single-value drop shim invoked with len != 1");
unsafe { core::ptr::drop_in_place::<T>(value.cast::<T>()) };
}
pub(crate) unsafe fn drop_shim_slice<T>(value: *mut u8, len: usize) {
let slice: *mut [T] = core::ptr::slice_from_raw_parts_mut(value.cast::<T>(), len);
unsafe { core::ptr::drop_in_place::<[T]>(slice) };
}
#[cfg_attr(feature = "std", allow(dead_code, reason = "exercised via tests; live call sites are no_std-only"))]
pub(crate) struct AbortOnUnwind;
impl Drop for AbortOnUnwind {
#[cfg_attr(coverage_nightly, coverage(off))]
#[cfg_attr(test, mutants::skip)] fn drop(&mut self) {
#[expect(clippy::panic, reason = "fatal-path abort: double-panic forces process termination")]
{
panic!("multitude: T::Drop panicked during replay_drops; aborting to prevent chunk leak");
}
}
}
pub(crate) unsafe fn replay_drop_entries(data: *mut u8, capacity: usize, count: usize) {
if count == 0 {
return;
}
let base = capacity - count * mem::size_of::<DropEntry>();
#[expect(
clippy::cast_ptr_alignment,
reason = "chunk payloads are CHUNK_ALIGN aligned; `data + base` is naturally `DropEntry`-aligned by construction"
)]
let entries_ptr = unsafe { data.add(base).cast::<DropEntry>() };
for i in 0..count {
let entry = unsafe { &*entries_ptr.add(i) };
let value_ptr = unsafe { data.add(entry.value_offset as usize) };
let f = entry.load_drop_fn(Ordering::Relaxed);
#[cfg(feature = "std")]
{
let _ = std::panic::catch_unwind(std::panic::AssertUnwindSafe(|| {
unsafe { f(value_ptr, entry.len as usize) };
}));
}
#[cfg(not(feature = "std"))]
{
let abort_guard = AbortOnUnwind;
unsafe { f(value_ptr, entry.len as usize) };
core::mem::forget(abort_guard);
}
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn replay_drop_entries_zero_count_is_noop() {
unsafe { replay_drop_entries(core::ptr::null_mut(), 0, 0) };
}
#[test]
fn round_payload_overflow_returns_none() {
assert!(round_payload(usize::MAX, 0).is_none());
}
#[test]
fn round_payload_header_plus_payload_overflow_returns_none() {
assert!(round_payload(usize::MAX, 1).is_none());
}
#[test]
fn round_payload_zero_rounds_to_zero() {
assert_eq!(round_payload(0, 0), Some(0));
}
#[test]
fn round_payload_rounds_up_to_alignment() {
let align = mem::align_of::<DropEntry>();
assert!(align > 1);
assert_eq!(round_payload(1, 0), Some(align));
}
#[test]
fn round_payload_compensates_for_header_misalignment() {
let align = mem::align_of::<DropEntry>();
let header = 2;
let payload = round_payload(1, header).expect("no overflow");
assert_eq!((header + payload) % align, 0);
assert!(payload >= 1);
}
#[test]
fn drop_entry_layout_matches_natural_alignment() {
let fn_align = mem::align_of::<unsafe fn(*mut u8, usize)>();
let raw = mem::size_of::<unsafe fn(*mut u8, usize)>() + 2 + 2;
let expected = raw.div_ceil(fn_align) * fn_align;
assert_eq!(mem::size_of::<DropEntry>(), expected);
assert_eq!(mem::align_of::<DropEntry>(), fn_align);
}
#[cfg(feature = "std")]
#[test]
fn abort_on_unwind_drop_panics() {
let result = std::panic::catch_unwind(|| {
let _guard = AbortOnUnwind;
});
assert!(result.is_err(), "AbortOnUnwind::drop must panic");
}
}