use stumpalo::{Arena, INITIAL_CHUNK_CAPACITY};
#[repr(align(64))]
#[allow(dead_code)]
struct Align64(u8);
#[repr(C)]
struct BigAlloc<const N: usize>([u8; N]);
#[test]
fn arena_size_is_32_bytes() {
assert_eq!(std::mem::size_of::<Arena>(), 32);
}
#[test]
fn new_creates_valid_arena() {
let arena = Arena::new();
assert!(!arena.has_fresh_chunks());
assert_eq!(arena.chunk_capacity(), 0);
let x = arena.alloc(42u32);
assert_eq!(*x, 42);
assert!(arena.chunk_capacity() > 0);
}
#[test]
fn allocates_default_chunk_size() {
let arena = Arena::new();
arena.alloc(1u32);
assert_eq!(
arena.chunk_capacity(),
INITIAL_CHUNK_CAPACITY - std::mem::size_of::<u32>()
);
}
#[test]
fn alloc_bool() {
let arena = Arena::new();
let a = arena.alloc(true);
let b = arena.alloc(false);
assert_eq!(*a, true);
assert_eq!(*b, false);
*b = true;
assert_eq!(*b, true);
}
#[test]
fn alloc_u8() {
let arena = Arena::new();
let x = arena.alloc(42u8);
assert_eq!(*x, 42);
*x = 255;
assert_eq!(*x, 255);
}
#[test]
fn alloc_i32() {
let arena = Arena::new();
let a = arena.alloc(-1i32);
let b = arena.alloc(0i32);
let c = arena.alloc(i32::MAX);
let d = arena.alloc(i32::MIN);
assert_eq!(*a, -1);
assert_eq!(*b, 0);
assert_eq!(*c, i32::MAX);
assert_eq!(*d, i32::MIN);
}
#[test]
fn alloc_f64() {
let arena = Arena::new();
let pi = arena.alloc(std::f64::consts::PI);
let e = arena.alloc(std::f64::consts::E);
assert!((*pi - std::f64::consts::PI).abs() < f64::EPSILON);
assert!((*e - std::f64::consts::E).abs() < f64::EPSILON);
}
#[test]
fn alloc_multiple_independent_mutations() {
let arena = Arena::new();
let a = arena.alloc(10u32);
let b = arena.alloc(20u32);
let c = arena.alloc(30u32);
*a += 1;
*b += 2;
*c += 3;
assert_eq!(*a, 11);
assert_eq!(*b, 22);
assert_eq!(*c, 33);
}
#[test]
fn alloc_tuple() {
let arena = Arena::new();
let t = arena.alloc((42u16, -7i8, 3.14f32));
assert_eq!(t.0, 42);
assert_eq!(t.1, -7);
assert!((t.2 - 3.14f32).abs() < f32::EPSILON);
t.0 = 100;
t.1 = -100;
assert_eq!(t.0, 100);
assert_eq!(t.1, -100);
}
#[test]
fn alloc_array() {
let arena = Arena::new();
let arr = arena.alloc([1u64, 2, 3, 4, 5]);
assert_eq!(*arr, [1, 2, 3, 4, 5]);
arr[2] = 99;
assert_eq!(arr[2], 99);
}
#[test]
fn alloc_respects_alignment() {
let arena = Arena::new();
let x = arena.alloc(0u16);
assert_eq!((x as *const u16 as usize) % 2, 0);
let y = arena.alloc(0u32);
assert_eq!((y as *const u32 as usize) % 4, 0);
let z = arena.alloc(0u64);
assert_eq!((z as *const u64 as usize) % 8, 0);
}
#[test]
fn alloc_alignment_64() {
let arena = Arena::new();
let _a = arena.alloc(1u8);
let x = arena.alloc(Align64(42));
assert_eq!((x as *const Align64 as usize) % 64, 0);
assert_eq!(x.0, 42);
}
#[test]
fn alloc_alignment_128_via_repr() {
#[repr(align(128))]
struct Align128(u8);
let arena = Arena::new();
let _a = arena.alloc(1u8);
let x = arena.alloc(Align128(99));
assert_eq!((x as *const Align128 as usize) % 128, 0);
assert_eq!(x.0, 99);
}
#[test]
fn alloc_many_different_sizes_preserves_alignment() {
let arena = Arena::new();
let _u8 = arena.alloc(0u8);
let u64 = arena.alloc(0u64);
let _u16 = arena.alloc(0u16);
let u128_val = arena.alloc(0u128);
let _u32 = arena.alloc(0u32);
assert_eq!((u64 as *const u64 as usize) % 8, 0);
assert_eq!((u128_val as *const u128 as usize) % 16, 0);
}
#[test]
fn fill_one_chunk_exactly() {
let arena = Arena::new();
let x = arena.alloc(0u128);
assert_eq!(*x, 0);
let mut prev_free = arena.chunk_capacity();
assert!(prev_free > 0);
for i in 1..(INITIAL_CHUNK_CAPACITY / 16) as u32 {
let x = arena.alloc(i as u128);
assert_eq!(*x, i as u128);
let curr_free = arena.chunk_capacity();
assert!(curr_free < prev_free);
prev_free = curr_free;
}
assert!(arena.chunk_capacity() < 16);
}
#[test]
fn alloc_past_one_chunk() {
let arena = Arena::new();
for i in 0..600u32 {
let x = arena.alloc(i as u64);
assert_eq!(*x, i as u64);
}
}
#[test]
fn alloc_way_past_one_chunk() {
let arena = Arena::new();
for i in 0..10000u64 {
let x = arena.alloc(i);
assert_eq!(*x, i);
}
}
#[test]
fn large_allocation_gets_own_chunk() {
let arena = Arena::new();
let fill_count = INITIAL_CHUNK_CAPACITY / std::mem::size_of::<u64>() - 1;
for _ in 0..fill_count {
let _x = arena.alloc(0u64);
}
let free_before_large = arena.chunk_capacity();
let over_half = INITIAL_CHUNK_CAPACITY / 2 + 1;
assert!(free_before_large < over_half);
const BIG: usize = (INITIAL_CHUNK_CAPACITY / 2) + 1;
let big = arena.alloc(BigAlloc::<BIG>([0; BIG]));
for i in 0..BIG {
big.0[i] = (i % 256) as u8;
}
for i in 0..BIG {
assert_eq!(big.0[i], (i % 256) as u8);
}
assert!(arena.chunk_capacity() > 0);
}
#[test]
fn large_allocation_does_not_affect_current_chunk_space() {
let arena = Arena::new();
let fill_count = INITIAL_CHUNK_CAPACITY / std::mem::size_of::<u64>() - 1;
for _ in 0..fill_count {
let _x = arena.alloc(0u64);
}
const BIG: usize = (INITIAL_CHUNK_CAPACITY / 2) + 100;
let large = arena.alloc(BigAlloc::<BIG>([0xAA; BIG]));
for byte in large.0.iter() {
assert_eq!(*byte, 0xAA);
}
assert!(arena.chunk_capacity() > 0);
}
#[test]
fn multiple_large_allocations() {
let arena = Arena::new();
let fill_count = INITIAL_CHUNK_CAPACITY / std::mem::size_of::<u64>() - 1;
for _ in 0..fill_count {
let _x = arena.alloc(0u64);
}
{
const SZ0: usize = (INITIAL_CHUNK_CAPACITY / 2) + 1;
let large = arena.alloc(BigAlloc::<SZ0>([0; SZ0]));
assert_eq!(large.0[0], 0);
}
{
const SZ1: usize = (INITIAL_CHUNK_CAPACITY / 2) + 101;
let large = arena.alloc(BigAlloc::<SZ1>([1; SZ1]));
assert_eq!(large.0[0], 1);
}
{
const SZ2: usize = (INITIAL_CHUNK_CAPACITY / 2) + 201;
let large = arena.alloc(BigAlloc::<SZ2>([2; SZ2]));
assert_eq!(large.0[0], 2);
}
assert!(arena.chunk_capacity() > 0);
}
#[test]
fn clear_resets_chunk_capacity() {
let mut arena = Arena::new();
let _a = arena.alloc(0u64);
let _b = arena.alloc(0u64);
let free_before_clear = arena.chunk_capacity();
arena.clear();
assert_eq!(arena.chunk_capacity(), INITIAL_CHUNK_CAPACITY);
assert!(arena.chunk_capacity() > free_before_clear);
}
#[test]
fn clear_makes_fresh_chunks_available() {
let mut arena = Arena::new();
for _ in 0..100 {
let _x = arena.alloc(0u64);
}
assert!(!arena.has_fresh_chunks());
arena.clear();
assert!(arena.has_fresh_chunks());
assert!(arena.chunk_capacity() >= INITIAL_CHUNK_CAPACITY);
}
#[test]
fn clear_then_alloc_reuses_fresh_chunks() {
let mut arena = Arena::new();
for i in 0..100u64 {
let x = arena.alloc(i);
assert_eq!(*x, i);
}
arena.clear();
let had_fresh = arena.has_fresh_chunks();
assert!(had_fresh);
let _a = arena.alloc(42u32);
let _b = arena.alloc(99u32);
assert_eq!(*_a, 42);
assert_eq!(*_b, 99);
}
#[test]
fn repeated_clear_and_alloc() {
let mut arena = Arena::new();
for cycle in 0..10 {
for i in 0..600u64 {
let x = arena.alloc((i * cycle) as u64);
assert_eq!(*x, (i * cycle) as u64);
}
arena.clear();
let _first = arena.alloc((cycle + 1) as u64);
}
}
#[test]
fn clear_multiple_times_builds_chunk_chain() {
let mut arena = Arena::new();
for _ in 0..600 {
let _x = arena.alloc(0u64);
}
arena.clear();
assert!(arena.has_fresh_chunks());
for _ in 0..600 {
let _x = arena.alloc(1u64);
}
arena.clear();
assert!(arena.has_fresh_chunks());
let x = arena.alloc(42u32);
assert_eq!(*x, 42);
}
#[test]
fn alloc_zst_unit() {
let arena = Arena::new();
let _unit = arena.alloc(());
let free_after_one = arena.chunk_capacity();
let _unit2 = arena.alloc(());
let _unit3 = arena.alloc(());
assert_eq!(arena.chunk_capacity(), free_after_one);
}
#[test]
fn alloc_zst_struct() {
#[derive(Debug, PartialEq)]
struct Zst;
let arena = Arena::new();
let _z = arena.alloc(Zst);
let free_after_one = arena.chunk_capacity();
let _z2 = arena.alloc(Zst);
assert_eq!(arena.chunk_capacity(), free_after_one);
}
#[test]
fn alloc_struct_with_drop() {
use std::sync::atomic::{AtomicU32, Ordering};
static DROP_COUNT: AtomicU32 = AtomicU32::new(0);
struct DropCounted {
_data: u64,
}
impl Drop for DropCounted {
fn drop(&mut self) {
DROP_COUNT.fetch_add(1, Ordering::Relaxed);
}
}
{
let arena = Arena::new();
let _x = arena.alloc(DropCounted { _data: 42 });
let _y = arena.alloc(DropCounted { _data: 99 });
}
assert_eq!(DROP_COUNT.load(Ordering::Relaxed), 0);
let arena = Arena::new();
let a = arena.alloc(DropCounted { _data: 1 });
let b = arena.alloc(DropCounted { _data: 2 });
assert_eq!(a._data, 1);
assert_eq!(b._data, 2);
}
#[test]
fn alloc_max_alignment_simd() {
#[repr(align(64))]
#[allow(dead_code)]
struct BigAlign([u8; 64]);
let arena = Arena::new();
let _pad = arena.alloc(1u8); let x = arena.alloc(BigAlign([0; 64]));
assert_eq!((x as *const BigAlign as usize) % 64, 0);
}
#[test]
fn alloc_exactly_one_byte() {
let arena = Arena::new();
let _ = arena.alloc(0u8); let free_before = arena.chunk_capacity();
let x = arena.alloc(0xFFu8);
assert_eq!(*x, 0xFF);
assert_eq!(arena.chunk_capacity(), free_before - 1);
}
#[test]
fn alloc_exactly_chunk_size_minus_one() {
let arena = Arena::new();
let count = INITIAL_CHUNK_CAPACITY / 8; for i in 0..count {
let x = arena.alloc(i as u64);
assert_eq!(*x, i as u64);
}
}
#[test]
fn alloc_after_filling_chunk_uses_new_chunk() {
let arena = Arena::new();
let x = arena.alloc(0u64);
assert_eq!(*x, 0);
let initial_free = arena.chunk_capacity();
assert!(initial_free > 0);
let u64_count = INITIAL_CHUNK_CAPACITY / 8;
let mut pprev_free = initial_free;
for _ in 1..u64_count {
let _x = arena.alloc(0u64);
let r = arena.chunk_capacity();
assert!(r < pprev_free);
pprev_free = r;
}
let x = arena.alloc(42u64);
assert_eq!(*x, 42);
}
#[test]
fn fuzz_random_types() {
let mut state: u64 = 0xDEADBEEF_CAFEBABE;
fn rand(state: &mut u64) -> u64 {
*state = state
.wrapping_mul(6364136223846793005)
.wrapping_add(1442695040888963407);
*state >> 33
}
let arena = Arena::new();
let mut ptrs: Vec<*const u8> = Vec::with_capacity(2000);
for _ in 0..2000 {
match rand(&mut state) % 6 {
0 => {
let x = arena.alloc(rand(&mut state) as u8);
ptrs.push(x as *const u8 as *const u8);
}
1 => {
let x = arena.alloc(rand(&mut state) as u16);
ptrs.push(x as *const u16 as *const u8);
}
2 => {
let x = arena.alloc(rand(&mut state) as u32);
ptrs.push(x as *const u32 as *const u8);
}
3 => {
let x = arena.alloc(rand(&mut state) as u64);
ptrs.push(x as *const u64 as *const u8);
}
4 => {
let x = arena.alloc([rand(&mut state) as u8; 16]);
ptrs.push(x.as_ptr());
}
5 => {
let x = arena.alloc([rand(&mut state) as u8; 64]);
ptrs.push(x.as_ptr());
}
_ => unreachable!(),
}
}
for p in &ptrs {
assert!(!p.is_null());
}
}
#[test]
fn fuzz_with_alignment_sensitive_types() {
let mut state: u64 = 0x12345678_9ABCDEF0;
fn rand(state: &mut u64) -> u64 {
*state = state
.wrapping_mul(6364136223846793005)
.wrapping_add(1442695040888963407);
*state >> 33
}
let arena = Arena::new();
for _ in 0..2000 {
match rand(&mut state) % 5 {
0 => {
let x = arena.alloc(rand(&mut state) as u8);
assert_eq!((x as *const u8 as usize) % 1, 0);
}
1 => {
let _pad = arena.alloc(rand(&mut state) as u8);
let x = arena.alloc(rand(&mut state) as u16);
assert_eq!((x as *const u16 as usize) % 2, 0);
}
2 => {
let x = arena.alloc(rand(&mut state) as u32);
assert_eq!((x as *const u32 as usize) % 4, 0);
}
3 => {
let x = arena.alloc(rand(&mut state) as u64);
assert_eq!((x as *const u64 as usize) % 8, 0);
}
4 => {
let val = rand(&mut state) as u8;
let arr = arena.alloc([val; 32]);
for byte in arr.iter() {
assert_eq!(*byte, val);
}
}
_ => unreachable!(),
}
}
}
#[test]
fn alloc_very_many_tiny_things() {
let arena = Arena::new();
for i in 0..100_000u32 {
let x = arena.alloc(i as u8);
assert_eq!(*x, i as u8);
}
}
#[test]
fn alloc_very_many_medium_things() {
let arena = Arena::new();
for i in 0..10_000u16 {
let allocated = arena.alloc([(i % 256) as u8; 10]);
assert_eq!(allocated[0], (i % 256) as u8);
}
}
#[test]
fn pointers_are_stable_across_allocations() {
let arena = Arena::new();
let a = arena.alloc(1u64) as *const u64;
let b = arena.alloc(2u64) as *const u64;
for _ in 0..500 {
let _x = arena.alloc(0u64);
}
unsafe {
assert_eq!(*a, 1);
assert_eq!(*b, 2);
}
}
#[test]
fn pointers_are_stable_after_clear_on_current_chunk() {
let mut arena = Arena::new();
let _a_ptr = arena.alloc(42u64) as *const u64;
arena.clear();
let b = arena.alloc(99u64);
assert_eq!(*b, 99);
}
#[test]
fn alloc_generic_struct() {
#[derive(Debug, PartialEq)]
struct Pair<T, U>(T, U);
let arena = Arena::new();
let p1 = arena.alloc(Pair(42u32, "hello"));
let p2 = arena.alloc(Pair(3.14f64, true));
assert_eq!(p1.0, 42);
assert_eq!(p1.1, "hello");
assert_eq!(p2.0, 3.14);
assert_eq!(p2.1, true);
}
#[test]
fn alloc_option() {
let arena = Arena::new();
let some = arena.alloc(Some(42u32));
let none: &mut Option<u32> = arena.alloc(None);
assert_eq!(*some, Some(42));
assert_eq!(*none, None);
*none = Some(7);
assert_eq!(*none, Some(7));
}
#[test]
fn alloc_result() {
let arena = Arena::new();
let ok: &mut Result<u32, &str> = arena.alloc(Ok(100));
let err: &mut Result<u32, &str> = arena.alloc(Err("oops"));
assert_eq!(*ok, Ok(100));
assert_eq!(*err, Err("oops"));
}
#[test]
fn clear_on_fresh_arena() {
let mut arena = Arena::new();
let free_before = arena.chunk_capacity();
assert!(!arena.has_fresh_chunks());
arena.clear();
assert_eq!(arena.chunk_capacity(), free_before);
assert!(!arena.has_fresh_chunks());
}
#[test]
fn clear_then_clear_again() {
let mut arena = Arena::new();
for _ in 0..INITIAL_CHUNK_CAPACITY / std::mem::size_of::<u64>() {
let _x = arena.alloc(0u64);
}
arena.clear();
let free_after_first_clear = arena.chunk_capacity();
assert!(!arena.has_fresh_chunks());
for _ in 0..INITIAL_CHUNK_CAPACITY / std::mem::size_of::<u64>() {
let _x = arena.alloc(0u64);
}
arena.clear();
assert_eq!(arena.chunk_capacity(), free_after_first_clear);
assert!(!arena.has_fresh_chunks()); }
#[test]
fn clear_and_reuse_multiple_chunks_round_robin() {
let mut arena = Arena::new();
let u64_per_chunk = INITIAL_CHUNK_CAPACITY / 8;
for _ in 0..u64_per_chunk * 3 {
let _x = arena.alloc(0u64);
}
arena.clear();
assert!(arena.has_fresh_chunks());
for _ in 0..u64_per_chunk * 2 {
let _x = arena.alloc(1u64);
}
arena.clear();
for i in 0..100u32 {
let x = arena.alloc(i);
assert_eq!(*x, i);
}
}
#[test]
fn large_allocation_exactly_half_chunk_does_not_trigger_own_chunk() {
let arena = Arena::new();
const HALF: usize = INITIAL_CHUNK_CAPACITY / 2;
let fill_count = INITIAL_CHUNK_CAPACITY / std::mem::size_of::<u64>() - 1;
for _ in 0..fill_count {
let _x = arena.alloc(0u64);
}
let free_before = arena.chunk_capacity();
assert!(free_before < HALF);
let _allocated = arena.alloc(BigAlloc::<HALF>([0x42; HALF]));
assert!(arena.chunk_capacity() > 0);
}
#[test]
fn large_allocation_just_over_half_chunk_gets_own_chunk() {
let arena = Arena::new();
const OVER_HALF: usize = INITIAL_CHUNK_CAPACITY / 2 + 1;
let fill_count = INITIAL_CHUNK_CAPACITY / std::mem::size_of::<u64>() - 1;
for _ in 0..fill_count {
let _x = arena.alloc(0u64);
}
let free_before = arena.chunk_capacity();
assert!(free_before < OVER_HALF);
let _allocated = arena.alloc(BigAlloc::<OVER_HALF>([0x42; OVER_HALF]));
assert!(arena.chunk_capacity() > 0);
}
#[test]
fn drop_arena_does_not_crash() {
let arena = Arena::new();
let _a = arena.alloc(1u32);
let _b = arena.alloc(2u64);
let _c = arena.alloc([0u8; 100]);
}
#[test]
fn drop_after_many_allocations() {
let arena = Arena::new();
for i in 0..5000u64 {
let _x = arena.alloc(i);
}
}
#[test]
fn drop_after_clear() {
let mut arena = Arena::new();
for _ in 0..500 {
let _x = arena.alloc(0u64);
}
arena.clear();
for _ in 0..500 {
let _x = arena.alloc(1u64);
}
}
#[test]
fn drop_after_large_allocations() {
let arena = Arena::new();
let fill_count = INITIAL_CHUNK_CAPACITY / std::mem::size_of::<u64>() - 1;
for _ in 0..fill_count {
let _x = arena.alloc(0u64);
}
const BIG: usize = INITIAL_CHUNK_CAPACITY / 2 + 50;
{
let _x = arena.alloc(BigAlloc::<BIG>([0; BIG]));
}
{
let _x = arena.alloc(BigAlloc::<BIG>([0; BIG]));
}
}
#[test]
fn drop_empty_arena() {
let _arena = Arena::new();
}
#[test]
fn stress_test_mixed_allocation_patterns() {
let mut state: u64 = 0xBEEF_FACE;
fn rand(state: &mut u64) -> u64 {
*state = state.wrapping_mul(1103515245).wrapping_add(12345);
*state
}
let mut arena = Arena::new();
for _cycle in 0..5 {
for _ in 0..200 {
match rand(&mut state) % 5 {
0 => {
let _ = arena.alloc(rand(&mut state) as u8);
}
1 => {
let _ = arena.alloc((rand(&mut state) as u32).wrapping_mul(42));
}
2 => {
let _ = arena.alloc(rand(&mut state) as u64);
}
3 => {
let _ = arena.alloc([rand(&mut state) as u8; 8]);
}
4 => {
let _ = arena.alloc([rand(&mut state) as u8; 32]);
}
_ => unreachable!(),
}
}
let _large1 = arena.alloc(BigAlloc::<{ INITIAL_CHUNK_CAPACITY / 2 + 50 }>(
[0xAA; INITIAL_CHUNK_CAPACITY / 2 + 50],
));
let _large2 = arena.alloc(BigAlloc::<{ INITIAL_CHUNK_CAPACITY / 2 + 200 }>(
[0xBB; INITIAL_CHUNK_CAPACITY / 2 + 200],
));
let _large3 = arena.alloc(BigAlloc::<{ INITIAL_CHUNK_CAPACITY / 2 + 300 }>(
[0xCC; INITIAL_CHUNK_CAPACITY / 2 + 300],
));
for _ in 0..100 {
match rand(&mut state) % 3 {
0 => {
let _ = arena.alloc(rand(&mut state) as u16);
}
1 => {
let _ = arena.alloc([rand(&mut state) as u32; 4]);
}
2 => {
let _ = arena.alloc([0xFFu8; 16]);
}
_ => unreachable!(),
}
}
arena.clear();
}
}
#[test]
fn multiple_clears_without_allocs() {
let mut arena = Arena::new();
let _x = arena.alloc(42u32);
arena.clear();
arena.clear();
arena.clear();
let y = arena.alloc(99u32);
assert_eq!(*y, 99);
}
#[test]
fn alloc_fixed_size_array() {
let arena = Arena::new();
let arr = arena.alloc([1u8, 2, 3, 4, 5]);
assert_eq!(*arr, [1, 2, 3, 4, 5]);
arr[2] = 99;
assert_eq!(arr[2], 99);
}
#[test]
fn alloc_medium_array() {
let arena = Arena::new();
let mut data = [0u8; 256];
for i in 0..256 {
data[i] = i as u8;
}
let arr = arena.alloc(data);
for i in 0..256 {
assert_eq!(arr[i], i as u8);
}
}
#[test]
fn alloc_returns_unique_mutable_reference() {
let arena = Arena::new();
let a = arena.alloc(0u32);
let b = arena.alloc(0u32);
*a = 42;
*b = 99;
assert_eq!(*a, 42);
assert_eq!(*b, 99);
}
#[test]
fn bespoke_allocation_first() {
let arena = Arena::new();
arena.alloc(INITIAL_CHUNK_CAPACITY + 1);
}
#[test]
fn can_clear_empty_arena() {
let mut arena = Arena::new();
arena.clear();
}
#[test]
fn alloc_str_basic() {
let arena = Arena::new();
let s = arena.alloc_str("hello world");
assert_eq!(s, "hello world");
s.make_ascii_uppercase();
assert_eq!(s, "HELLO WORLD");
}
#[test]
fn alloc_str_empty() {
let arena = Arena::new();
let s = arena.alloc_str("");
assert_eq!(s, "");
assert_eq!(s.len(), 0);
}
#[test]
fn alloc_str_multi_byte() {
let arena = Arena::new();
let s = arena.alloc_str("a̐éõ🦀");
assert_eq!(s, "a̐éõ🦀");
}
#[test]
fn alloc_str_long() {
let arena = Arena::new();
let data = "x".repeat(2000);
let s = arena.alloc_str(&data);
assert_eq!(*s, data);
let mut arena = Arena::new();
let s1 = arena.alloc_str("first");
assert_eq!(s1, "first");
arena.clear();
let s2 = arena.alloc_str("second");
assert_eq!(s2, "second");
}
#[test]
fn alloc_str_past_one_chunk() {
let arena = Arena::new();
arena.alloc_str("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaa");
let s = arena.alloc_str("hello from second chunk");
assert_eq!(s, "hello from second chunk");
}
#[test]
fn alloc_slice_copy_basic() {
let arena = Arena::new();
let slice = arena.alloc_slice_copy(&[1, 2, 3, 4]);
assert_eq!(slice, [1, 2, 3, 4]);
slice[0] = 99;
assert_eq!(slice, [99, 2, 3, 4]);
}
#[test]
fn alloc_slice_copy_empty() {
let arena = Arena::new();
let slice = arena.alloc_slice_copy(&[] as &[u8]);
assert!(slice.is_empty());
}
#[test]
fn alloc_slice_copy_long() {
let arena = Arena::new();
let data = vec![0xABu8; 1024];
let slice = arena.alloc_slice_copy(&data);
assert_eq!(slice, data);
}
#[test]
fn alloc_slice_copy_with_clear() {
let mut arena = Arena::new();
let s1 = arena.alloc_slice_copy(b"first");
assert_eq!(s1, b"first");
arena.clear();
let s2 = arena.alloc_slice_copy(b"second");
assert_eq!(s2, b"second");
}
#[test]
fn alloc_slice_copy_past_one_chunk() {
let arena = Arena::new();
arena.alloc_slice_copy(&[0; 30]);
let slice = arena.alloc_slice_copy(b"hello from second chunk");
assert_eq!(slice, b"hello from second chunk");
}
#[test]
fn arena_forwarding_alloc() {
let root = Arena::new();
let x = root.alloc(42u32);
assert_eq!(*x, 42);
*x = 99;
assert_eq!(*x, 99);
}
#[test]
fn arena_forwarding_alloc_with() {
let root = Arena::new();
let x = root.alloc_with(|| [1, 2, 3]);
assert_eq!(x, &[1, 2, 3]);
}
#[test]
fn arena_forwarding_alloc_slice_copy() {
let root = Arena::new();
let slice = root.alloc_slice_copy(&[10, 20, 30]);
assert_eq!(slice, &[10, 20, 30]);
}
#[test]
fn arena_forwarding_alloc_str() {
let root = Arena::new();
let s = root.alloc_str("hello");
assert_eq!(s, "hello");
}
#[test]
fn arena_forwarding_allocated_bytes() {
let root = Arena::new();
let _ = root.alloc(42u32);
assert!(root.allocated_bytes() > 0);
}
#[test]
fn arena_forwarding_sized_slice() {
let root = Arena::new();
let arr = root.alloc_sized_slice_fill_default::<u32, 4>();
assert_eq!(arr, &[0, 0, 0, 0]);
}
#[test]
fn with_scope_basic() {
let mut arena = Arena::new();
arena.with_scope(|scope| {
let x = scope.alloc(42u32);
assert_eq!(*x, 42);
*x = 99;
assert_eq!(*x, 99);
});
}
#[test]
fn with_scope_nested() {
let mut arena = Arena::new();
arena.alloc(1u32);
let cap = arena.chunk_capacity();
arena.with_scope(|outer_scope| {
let a = outer_scope.alloc(2u32);
outer_scope.with_scope(|inner_scope| {
let inner = inner_scope.alloc(3u32);
assert_eq!(*inner, 3);
for i in 0..10 {
let v = inner_scope.alloc(i as u128);
assert_eq!(*v, i as u128);
}
});
let after = outer_scope.alloc(4u32);
assert_eq!(*after, 4);
assert_eq!(*a, 2);
});
assert_eq!(arena.chunk_capacity(), cap);
}
#[test]
fn with_scope_outer_preserved() {
let mut arena = Arena::new();
let x_addr = arena.alloc(10u32) as *mut u32;
let y_addr = arena.alloc(20u32) as *mut u32;
let b_addr = arena.alloc(0xFFu8) as *mut u8;
arena.with_scope(|scope| {
for i in 0..30 {
let v = scope.alloc(i as u128);
*v = (i * 2) as u128;
assert_eq!(*v, (i * 2) as u128);
}
});
assert_eq!(unsafe { *x_addr }, 10);
assert_eq!(unsafe { *y_addr }, 20);
assert_eq!(unsafe { *b_addr }, 0xFF);
let new_int = arena.alloc(999u32);
assert_eq!(*new_int, 999);
}
#[test]
fn with_scope_multiple_sequential() {
let mut arena = Arena::new();
let arena = arena.as_arena_ref_mut();
let a_addr = arena.alloc(1u32) as *mut u32;
assert_eq!(unsafe { *a_addr }, 1);
arena.with_scope(|scope| {
let x = scope.alloc(100u32);
*x = *x + 1;
assert_eq!(*x, 101);
});
assert_eq!(unsafe { *a_addr }, 1);
arena.with_scope(|scope| {
let y = scope.alloc(200u32);
*y = *y + 2;
assert_eq!(*y, 202);
});
assert_eq!(unsafe { *a_addr }, 1);
let b = arena.alloc(2u32);
assert_eq!(*b, 2);
}
#[test]
fn with_scope_reuses_chunks() {
let mut arena = Arena::new();
arena.alloc(1u32);
let cap_after_first = arena.chunk_capacity();
assert!(cap_after_first > 0);
assert!(!arena.has_fresh_chunks());
arena.with_scope(|scope| {
scope.alloc(0u128);
});
assert_eq!(arena.chunk_capacity(), cap_after_first);
assert!(!arena.has_fresh_chunks());
assert!(!arena.has_fresh_chunks());
arena.with_scope(|scope| {
for _ in 0..100 {
scope.alloc(0u128);
}
});
assert_eq!(arena.chunk_capacity(), cap_after_first);
assert!(arena.has_fresh_chunks());
}
#[test]
fn alloc_str_lit_basic() {
let arena = Arena::new();
let s = arena.alloc_str_lit("hello world");
assert_eq!(s, "hello world");
s.make_ascii_uppercase();
assert_eq!(s, "HELLO WORLD");
}
#[test]
fn alloc_str_lit_empty() {
let arena = Arena::new();
let s = arena.alloc_str_lit("");
assert_eq!(s, "");
assert_eq!(s.len(), 0);
}
#[test]
fn alloc_str_lit_multi_byte() {
let arena = Arena::new();
let s = arena.alloc_str_lit("a̐éõ🦀");
assert_eq!(s, "a̐éõ🦀");
}
#[test]
fn alloc_str_lit_with_clear() {
let mut arena = Arena::new();
let s1 = arena.alloc_str_lit("first");
assert_eq!(s1, "first");
arena.clear();
let s2 = arena.alloc_str_lit("second");
assert_eq!(s2, "second");
}
#[test]
fn alloc_str_lit_past_one_chunk() {
let arena = Arena::new();
arena.alloc_str("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaa");
let s = arena.alloc_str_lit("hello from second chunk");
assert_eq!(s, "hello from second chunk");
}
#[test]
fn alloc_str_lit_many() {
let arena = Arena::new();
for _ in 0..1000 {
let s = arena.alloc_str_lit("fast path");
assert_eq!(s, "fast path");
}
}
#[test]
fn alloc_slice_lit_copy_basic() {
let arena = Arena::new();
let slice = arena.alloc_slice_lit_copy(&[1, 2, 3, 4]);
assert_eq!(slice, [1, 2, 3, 4]);
slice[0] = 99;
assert_eq!(slice, [99, 2, 3, 4]);
}
#[test]
fn alloc_slice_lit_copy_empty() {
let arena = Arena::new();
let slice = arena.alloc_slice_lit_copy(&[] as &[u8]);
assert!(slice.is_empty());
}
#[test]
fn alloc_slice_lit_copy_with_clear() {
let mut arena = Arena::new();
let s1 = arena.alloc_slice_lit_copy(b"first");
assert_eq!(s1, b"first");
arena.clear();
let s2 = arena.alloc_slice_lit_copy(b"second");
assert_eq!(s2, b"second");
}
#[test]
fn alloc_slice_lit_copy_past_one_chunk() {
let arena = Arena::new();
arena.alloc_slice_copy(&[0; 30]);
let slice = arena.alloc_slice_lit_copy(b"hello from second chunk");
assert_eq!(slice, b"hello from second chunk");
}
#[test]
fn alloc_slice_lit_copy_many() {
let arena = Arena::new();
for _ in 0..1000 {
let s = arena.alloc_slice_lit_copy(&[1u8, 2, 3, 4, 5, 6, 7, 8]);
assert_eq!(s, [1, 2, 3, 4, 5, 6, 7, 8]);
}
}
#[test]
fn alloc_slice_lit_copy_f64() {
let arena = Arena::new();
let slice = arena.alloc_slice_lit_copy(&[1.0f64, 2.5, 3.14]);
assert!((slice[0] - 1.0).abs() < f64::EPSILON);
assert!((slice[1] - 2.5).abs() < f64::EPSILON);
assert!((slice[2] - 3.14).abs() < f64::EPSILON);
slice[1] = 99.9;
assert!((slice[1] - 99.9).abs() < f64::EPSILON);
}
#[test]
#[should_panic]
fn over_allocation_alloc_slice_fill_with_u8() {
let arena = Arena::new();
let too_big = (isize::MAX as usize).saturating_add(1);
let _: &mut [u8] = arena.alloc_slice_fill_with(too_big, |_| 0u8);
}
#[test]
#[should_panic]
fn over_allocation_alloc_slice_fill_with_u64() {
let arena = Arena::new();
let too_big = (isize::MAX as usize / 8).saturating_add(1);
let _: &mut [u64] = arena.alloc_slice_fill_with(too_big, |_| 0);
}
#[test]
#[should_panic]
fn over_allocation_alloc_slice_fill_default() {
let arena = Arena::new();
let too_big = (isize::MAX as usize).saturating_add(1);
let _: &mut [u8] = arena.alloc_slice_fill_default(too_big);
}
#[test]
#[should_panic]
fn over_allocation_alloc_slice_try_fill_with() {
let arena = Arena::new();
let too_big = (isize::MAX as usize).saturating_add(1);
let _: Result<&mut [u8], ()> = arena.alloc_slice_try_fill_with(too_big, |_| Ok(0u8));
}