#![cfg(all(feature = "alloc-global", feature = "fastbin"))]
use std::alloc::Layout;
use std::collections::HashSet;
use std::sync::atomic::{AtomicBool, Ordering};
use sefer_alloc::registry::{bootstrap, HeapRegistry};
static SERIAL: AtomicBool = AtomicBool::new(false);
struct SerialGuard;
impl SerialGuard {
fn acquire() -> Self {
while SERIAL
.compare_exchange(false, true, Ordering::Acquire, Ordering::Relaxed)
.is_err()
{
std::hint::spin_loop();
}
SerialGuard
}
}
impl Drop for SerialGuard {
fn drop(&mut self) {
SERIAL.store(false, Ordering::Release);
}
}
fn xorshift64(state: &mut u64) -> u64 {
let mut x = *state;
x ^= x << 13;
x ^= x >> 7;
x ^= x << 17;
*state = x;
x
}
#[test]
fn t1_round_trip() {
let _serial = SerialGuard::acquire();
let _ = bootstrap::ensure();
let heap = HeapRegistry::claim();
assert!(!heap.is_null(), "HeapRegistry::claim returned null");
const K: usize = 64;
const OPS: usize = 1024;
let layout = Layout::from_size_align(16, 8).unwrap();
let mut live: Vec<*mut u8> = Vec::with_capacity(K);
for i in 0..K {
let p = unsafe { (*heap).alloc(layout) };
assert!(!p.is_null(), "initial alloc returned null at {i}");
unsafe { core::ptr::write_bytes(p, 0xAA, 16) };
live.push(p);
}
let mut set: HashSet<usize> = HashSet::with_capacity(K);
for &p in &live {
assert!(set.insert(p as usize), "duplicate pointer in initial fill");
}
let mut rng: u64 = 0xCAFE;
for iter in 0..OPS {
let idx = (xorshift64(&mut rng) as usize) % K;
unsafe { (*heap).dealloc(live[idx], layout) };
let p = unsafe { (*heap).alloc(layout) };
assert!(!p.is_null(), "alloc returned null at iteration {iter}");
unsafe { core::ptr::write_bytes(p, (iter & 0xFF) as u8, 16) };
live[idx] = p;
set.clear();
for &lp in &live {
assert!(
set.insert(lp as usize),
"duplicate live pointer at iteration {iter}"
);
}
}
for p in &live {
unsafe { (*heap).dealloc(*p, layout) };
}
unsafe { HeapRegistry::recycle(heap) };
}
#[test]
fn t7_conservation() {
let _serial = SerialGuard::acquire();
let _ = bootstrap::ensure();
let heap = HeapRegistry::claim();
assert!(!heap.is_null(), "HeapRegistry::claim returned null");
const N: usize = 128;
const ROUNDS: usize = 100;
let layout = Layout::from_size_align(32, 8).unwrap();
for round in 0..ROUNDS {
let mut ptrs: Vec<*mut u8> = Vec::with_capacity(N);
for i in 0..N {
let p = unsafe { (*heap).alloc(layout) };
assert!(!p.is_null(), "alloc returned null at round {round}, i={i}");
unsafe { core::ptr::write_bytes(p, (round & 0xFF) as u8, 32) };
ptrs.push(p);
}
for &p in ptrs.iter().rev() {
unsafe { (*heap).dealloc(p, layout) };
}
}
let p = unsafe { (*heap).alloc(layout) };
assert!(
!p.is_null(),
"final alloc returned null after conservation loop"
);
unsafe {
core::ptr::write_bytes(p, 0x55, 32);
assert_eq!(p.read(), 0x55, "final read-back mismatch");
(*heap).dealloc(p, layout);
}
unsafe { HeapRegistry::recycle(heap) };
}
#[test]
fn t_bulk_overflow() {
let _serial = SerialGuard::acquire();
let _ = bootstrap::ensure();
let heap = HeapRegistry::claim();
assert!(!heap.is_null(), "HeapRegistry::claim returned null");
const TOTAL: usize = 1000;
let layout = Layout::from_size_align(16, 8).unwrap();
let mut ptrs: Vec<*mut u8> = Vec::with_capacity(TOTAL);
for i in 0..TOTAL {
let p = unsafe { (*heap).alloc(layout) };
assert!(!p.is_null(), "alloc returned null at i={i}");
unsafe { core::ptr::write_bytes(p, (i & 0xFF) as u8, 16) };
ptrs.push(p);
}
let set: HashSet<usize> = ptrs.iter().map(|&p| p as usize).collect();
assert_eq!(
set.len(),
TOTAL,
"expected {TOTAL} distinct pointers, got {}",
set.len()
);
for &p in &ptrs {
unsafe { (*heap).dealloc(p, layout) };
}
unsafe { HeapRegistry::recycle(heap) };
}