use core::num::NonZeroUsize;
use super::{
BytePool, BytePoolLeaseOutcome, BytePoolMaterializeOutcome, BytePoolRecycleOutcome,
BytePoolReserveOutcome, BytePoolResumeOutcome, BytePoolStatistics,
};
fn nonzero(value: usize) -> Result<NonZeroUsize, &'static str> {
NonZeroUsize::new(value).ok_or("test capacity was zero")
}
#[test]
fn leases_borrow_exact_pool_storage_and_recycle_on_drop() -> Result<(), &'static str> {
let mut pool = BytePool::try_new(nonzero(16)?, nonzero(4)?).map_err(|_| "pool unavailable")?;
let BytePoolLeaseOutcome::Leased(mut first) = pool.lease(nonzero(6)?) else {
return Err("first extent was unavailable");
};
let first_address = first.bytes().as_ptr();
first.bytes_mut().copy_from_slice(b"first!");
assert_eq!(first.byte_capacity(), 6);
assert_eq!(first.bytes(), b"first!");
drop(first);
assert_eq!(
pool.statistics(),
BytePoolStatistics {
byte_capacity: 16,
free_byte_capacity: 16,
maximum_lease_count: 4,
active_lease_count: 0,
}
);
let BytePoolLeaseOutcome::Leased(second) = pool.lease(nonzero(16)?) else {
return Err("coalesced extent was unavailable");
};
assert_eq!(second.byte_capacity(), 16);
assert_eq!(second.bytes().as_ptr(), first_address);
Ok(())
}
#[test]
fn retained_extents_resume_without_moving_and_do_not_block_other_extents()
-> Result<(), &'static str> {
let mut pool = BytePool::try_new(nonzero(16)?, nonzero(4)?).map_err(|_| "pool unavailable")?;
let BytePoolLeaseOutcome::Leased(mut retained) = pool.lease(nonzero(8)?) else {
return Err("retained extent was unavailable");
};
retained.bytes_mut().copy_from_slice(b"retained");
let retained_address = retained.bytes().as_ptr();
let retained = retained.retain();
let BytePoolLeaseOutcome::Leased(mut independent) = pool.lease(nonzero(8)?) else {
return Err("independent extent was unavailable");
};
independent.bytes_mut().copy_from_slice(b"separate");
assert_ne!(independent.bytes().as_ptr(), retained_address);
drop(independent);
assert_eq!(pool.statistics().free_byte_capacity, 8);
let BytePoolResumeOutcome::Resumed(resumed) = pool.resume(retained) else {
return Err("retained extent did not resume");
};
assert_eq!(resumed.bytes(), b"retained");
assert_eq!(resumed.bytes().as_ptr(), retained_address);
drop(resumed);
assert_eq!(pool.statistics().free_byte_capacity, 16);
Ok(())
}
#[test]
fn byte_and_lease_exhaustion_remain_distinct() -> Result<(), &'static str> {
let mut bytes = BytePool::try_new(nonzero(4)?, nonzero(2)?).map_err(|_| "pool unavailable")?;
let BytePoolLeaseOutcome::Leased(first) = bytes.lease(nonzero(4)?) else {
return Err("first byte extent was unavailable");
};
let first = first.retain();
assert!(matches!(
bytes.lease(nonzero(1)?),
BytePoolLeaseOutcome::Exhausted { .. }
));
assert_eq!(bytes.recycle(first), BytePoolRecycleOutcome::Recycled);
let mut leases = BytePool::try_new(nonzero(8)?, nonzero(1)?).map_err(|_| "pool unavailable")?;
let BytePoolLeaseOutcome::Leased(first) = leases.lease(nonzero(4)?) else {
return Err("first lease was unavailable");
};
let first = first.retain();
assert!(matches!(
leases.lease(nonzero(1)?),
BytePoolLeaseOutcome::LeaseCapacityReached { .. }
));
assert_eq!(leases.recycle(first), BytePoolRecycleOutcome::Recycled);
Ok(())
}
#[test]
fn retained_leases_can_be_explicitly_recycled() -> Result<(), &'static str> {
let mut pool = BytePool::try_new(nonzero(8)?, nonzero(2)?).map_err(|_| "pool unavailable")?;
let BytePoolLeaseOutcome::Leased(lease) = pool.lease(nonzero(8)?) else {
return Err("lease was unavailable");
};
let retained = lease.retain();
assert_eq!(retained.byte_capacity(), 8);
assert_eq!(pool.recycle(retained), BytePoolRecycleOutcome::Recycled);
assert_eq!(pool.statistics().free_byte_capacity, 8);
Ok(())
}
#[test]
fn dropped_reservations_do_not_materialize_leases() -> Result<(), &'static str> {
let mut pool = BytePool::try_new(nonzero(16)?, nonzero(2)?).map_err(|_| "pool unavailable")?;
let BytePoolReserveOutcome::Reserved(reservation) = pool.reserve_exact(nonzero(12)?) else {
return Err("reservation was unavailable");
};
assert_eq!(reservation.reserved_maximum(), nonzero(12)?);
drop(reservation);
assert_eq!(pool.leases.first().map(|lease| lease.generation), Some(0));
assert_eq!(pool.statistics().free_byte_capacity, 16);
Ok(())
}
#[test]
fn reservations_materialize_only_the_requested_tail() -> Result<(), &'static str> {
let mut pool = BytePool::try_new(nonzero(16)?, nonzero(2)?).map_err(|_| "pool unavailable")?;
let BytePoolReserveOutcome::Reserved(reservation) = pool.reserve_exact(nonzero(12)?) else {
return Err("reservation was unavailable");
};
let BytePoolMaterializeOutcome::Leased(lease) = reservation.materialize(nonzero(3)?) else {
return Err("reserved tail was unavailable");
};
assert_eq!(lease.byte_capacity(), 3);
drop(lease);
assert_eq!(pool.statistics().free_byte_capacity, 16);
Ok(())
}
#[test]
fn out_of_order_releases_coalesce_without_global_sorting() -> Result<(), &'static str> {
let mut pool = BytePool::try_new(nonzero(16)?, nonzero(4)?).map_err(|_| "pool unavailable")?;
let BytePoolLeaseOutcome::Leased(first) = pool.lease(nonzero(4)?) else {
return Err("first lease unavailable");
};
let first = first.retain();
let BytePoolLeaseOutcome::Leased(second) = pool.lease(nonzero(4)?) else {
return Err("second lease unavailable");
};
let second = second.retain();
let BytePoolLeaseOutcome::Leased(third) = pool.lease(nonzero(4)?) else {
return Err("third lease unavailable");
};
let third = third.retain();
let BytePoolLeaseOutcome::Leased(fourth) = pool.lease(nonzero(4)?) else {
return Err("fourth lease unavailable");
};
let fourth = fourth.retain();
assert_eq!(pool.recycle(second), BytePoolRecycleOutcome::Recycled);
assert_eq!(pool.recycle(fourth), BytePoolRecycleOutcome::Recycled);
assert!(matches!(
pool.reserve_exact(nonzero(8)?),
BytePoolReserveOutcome::Exhausted { .. }
));
assert_eq!(pool.recycle(first), BytePoolRecycleOutcome::Recycled);
assert_eq!(pool.recycle(third), BytePoolRecycleOutcome::Recycled);
let BytePoolLeaseOutcome::Leased(coalesced) = pool.lease(nonzero(16)?) else {
return Err("coalesced lease unavailable");
};
assert_eq!(coalesced.byte_capacity(), 16);
Ok(())
}
#[cfg(feature = "performance-evidence")]
#[test]
fn evidence_accounts_for_pool_searches_and_lease_lifetimes() -> Result<(), &'static str> {
let mut pool = BytePool::try_new(nonzero(16)?, nonzero(2)?).map_err(|_| "pool unavailable")?;
let BytePoolLeaseOutcome::Leased(lease) = pool.lease(nonzero(6)?) else {
return Err("lease unavailable");
};
let retained = lease.retain();
let BytePoolResumeOutcome::Resumed(resumed) = pool.resume(retained) else {
return Err("retained lease unavailable");
};
drop(resumed);
let evidence = pool.take_evidence();
assert_eq!(evidence.active_leases_at_start(), 0);
assert_eq!(evidence.reservation_attempts().total(), 1);
assert_eq!(evidence.requested_bytes().total(), 6);
assert_eq!(evidence.free_extents_examined().total(), 1);
assert_eq!(evidence.free_extent_count_high_water().maximum(), 1);
assert_eq!(evidence.reservations().total(), 1);
assert_eq!(evidence.materializations().total(), 1);
assert_eq!(evidence.materialized_bytes().total(), 6);
assert_eq!(evidence.resume_attempts().total(), 1);
assert_eq!(evidence.resumed_leases().total(), 1);
assert_eq!(evidence.released_leases_collected().total(), 1);
assert_eq!(evidence.active_leases().current(), 0);
assert_eq!(evidence.active_leases().high_water().maximum(), 1);
assert!(evidence.valid());
assert_eq!(pool.evidence(), super::BytePoolEvidence::new());
Ok(())
}
#[test]
fn bounded_reservations_report_contiguous_capacity_without_consuming_it() -> Result<(), &'static str>
{
let mut pool = BytePool::try_new(nonzero(16)?, nonzero(4)?).map_err(|_| "pool")?;
let BytePoolLeaseOutcome::Leased(first) = pool.lease(nonzero(4)?) else {
return Err("first lease");
};
let first = first.retain();
let BytePoolLeaseOutcome::Leased(middle) = pool.lease(nonzero(4)?) else {
return Err("middle lease");
};
let middle = middle.retain();
assert_eq!(pool.recycle(first), BytePoolRecycleOutcome::Recycled);
let before = pool.statistics();
assert_eq!(pool.byte_capacity(), 16);
assert_eq!(before.free_byte_capacity, 12);
for (requested, expected) in [(16, 8), (6, 6), (1, 1), (9, 8)] {
let BytePoolReserveOutcome::Reserved(reservation) = pool.reserve_up_to(nonzero(requested)?)
else {
return Err("available contiguous extent refused");
};
assert_eq!(reservation.reserved_maximum().get(), expected);
drop(reservation);
assert_eq!(pool.statistics(), before);
}
let BytePoolReserveOutcome::Reserved(reservation) = pool.reserve_up_to(nonzero(16)?) else {
return Err("final reservation");
};
let BytePoolMaterializeOutcome::Leased(lease) = reservation.materialize(nonzero(3)?) else {
return Err("reserved prefix refused");
};
assert_eq!(lease.byte_capacity(), 3);
drop(lease);
assert_eq!(pool.statistics(), before);
assert_eq!(pool.recycle(middle), BytePoolRecycleOutcome::Recycled);
let BytePoolReserveOutcome::Reserved(reservation) = pool.reserve_up_to(nonzero(16)?) else {
return Err("coalesced reservation");
};
assert_eq!(reservation.reserved_maximum().get(), 16);
Ok(())
}
#[test]
fn matching_metadata_from_another_pool_cannot_resume_or_recycle_local_storage()
-> Result<(), &'static str> {
for recycle in [false, true] {
let mut first = BytePool::try_new(nonzero(8)?, nonzero(1)?).map_err(|_| "first pool")?;
let mut second = BytePool::try_new(nonzero(8)?, nonzero(1)?).map_err(|_| "second pool")?;
let BytePoolLeaseOutcome::Leased(mut a) = first.lease(nonzero(8)?) else {
return Err("first lease");
};
a.bytes_mut().copy_from_slice(b"original");
let a = a.retain();
let BytePoolLeaseOutcome::Leased(mut b) = second.lease(nonzero(8)?) else {
return Err("second lease");
};
b.bytes_mut().copy_from_slice(b"separate");
let b = b.retain();
let a = if recycle {
let BytePoolRecycleOutcome::Unavailable { retained } = second.recycle(a) else {
return Err("foreign token recycled local storage");
};
retained
} else {
let BytePoolResumeOutcome::Unavailable { retained } = second.resume(a) else {
return Err("foreign token resumed local storage");
};
retained
};
let BytePoolResumeOutcome::Resumed(a) = first.resume(a) else {
return Err("refused owner could not resume its own storage");
};
assert_eq!(a.bytes(), b"original");
let BytePoolResumeOutcome::Resumed(b) = second.resume(b) else {
return Err("foreign refusal changed local storage");
};
assert_eq!(b.bytes(), b"separate");
}
Ok(())
}
#[test]
fn either_address_reuse_alone_cannot_rebind_a_retained_owner() -> Result<(), &'static str> {
for reuse_backing_address in [false, true] {
let mut first = BytePool::try_new(nonzero(8)?, nonzero(1)?).map_err(|_| "first")?;
let mut second = BytePool::try_new(nonzero(8)?, nonzero(1)?).map_err(|_| "second")?;
let BytePoolLeaseOutcome::Leased(lease) = first.lease(nonzero(8)?) else {
return Err("first lease");
};
let mut foreign = lease.retain();
let BytePoolLeaseOutcome::Leased(lease) = second.lease(nonzero(8)?) else {
return Err("second lease");
};
let local = lease.retain();
let original_pool_address = foreign.pool_address;
let record = second.leases.first_mut().ok_or("slot")?;
let original_identity_address = record.identity_address;
if reuse_backing_address {
foreign.pool_address = second.storage.as_ptr().addr();
} else {
record.identity_address = foreign.identity.as_ptr().addr();
}
assert_ne!(foreign, local);
let BytePoolResumeOutcome::Unavailable { mut retained } = second.resume(foreign) else {
return Err("one reused address rebound ownership");
};
retained.pool_address = original_pool_address;
second.leases.first_mut().ok_or("slot")?.identity_address = original_identity_address;
assert_eq!(first.recycle(retained), BytePoolRecycleOutcome::Recycled);
assert_eq!(second.recycle(local), BytePoolRecycleOutcome::Recycled);
}
Ok(())
}
#[test]
fn pool_moves_and_destroyed_origins_preserve_token_identity() -> Result<(), &'static str> {
fn requires_send<T: Send>() {}
requires_send::<BytePool>();
requires_send::<super::RetainedByteLease>();
let mut pool = BytePool::try_new(nonzero(8)?, nonzero(1)?).map_err(|_| "pool")?;
let BytePoolLeaseOutcome::Leased(mut lease) = pool.lease(nonzero(8)?) else {
return Err("lease");
};
lease.bytes_mut().copy_from_slice(b"movable!");
let retained = lease.retain();
let mut moved = alloc::boxed::Box::new(pool);
let BytePoolResumeOutcome::Resumed(lease) = moved.resume(retained) else {
return Err("move changed owner");
};
assert_eq!(lease.bytes(), b"movable!");
let mut stale = lease.retain();
drop(moved);
for _ in 0..64 {
let mut replacement =
BytePool::try_new(nonzero(8)?, nonzero(1)?).map_err(|_| "replacement")?;
let BytePoolLeaseOutcome::Leased(lease) = replacement.lease(nonzero(8)?) else {
return Err("replacement lease");
};
let local = lease.retain();
let BytePoolRecycleOutcome::Unavailable { retained } = replacement.recycle(stale) else {
return Err("destroyed origin rebound to replacement");
};
stale = retained;
assert_eq!(replacement.recycle(local), BytePoolRecycleOutcome::Recycled);
}
Ok(())
}
proptest::proptest! {
#[test]
fn arbitrary_owner_operations_preserve_live_bytes(
operations in proptest::collection::vec((0_usize..2, 0_u8..5, 1_usize..=16), 0..128)
) {
use proptest::{prop_assert, prop_assert_eq, test_runner::TestCaseError};
let capacity = nonzero(16).map_err(TestCaseError::fail)?;
let mut pools = [
BytePool::try_new(capacity, NonZeroUsize::MIN).map_err(|_| TestCaseError::fail("first pool"))?,
BytePool::try_new(capacity, NonZeroUsize::MIN).map_err(|_| TestCaseError::fail("second pool"))?,
];
let mut retained: [Option<(super::RetainedByteLease, usize, u8)>; 2] = [None, None];
for (owner, action, size) in operations {
let other = if owner == 0 { 1 } else { 0 };
let pool = pools.get_mut(owner).ok_or_else(|| TestCaseError::fail("owner"))?;
let held = retained.get_mut(owner).ok_or_else(|| TestCaseError::fail("retained owner"))?;
match (action, held.take()) {
(0, None) => {
let BytePoolLeaseOutcome::Leased(mut lease) = pool.lease(nonzero(size).map_err(TestCaseError::fail)?) else {
return Err(proptest::test_runner::TestCaseError::fail("free owner refused"));
};
let value = u8::try_from(size).map_err(|_| TestCaseError::fail("byte"))?;
lease.bytes_mut().fill(value);
*held = Some((lease.retain(), size, value));
}
(1 | 2, Some((token, size, value))) => {
let BytePoolResumeOutcome::Resumed(lease) = pool.resume(token) else {
return Err(proptest::test_runner::TestCaseError::fail("right owner refused"));
};
prop_assert_eq!(lease.byte_capacity(), size);
prop_assert!(lease.bytes().iter().all(|byte| *byte == value));
if action == 1 {
*held = Some((lease.retain(), size, value));
}
}
(3, Some((token, _, _))) => {
prop_assert_eq!(pool.recycle(token), BytePoolRecycleOutcome::Recycled);
}
(4, Some((token, size, value))) => {
let other_pool = pools.get_mut(other).ok_or_else(|| TestCaseError::fail("other owner"))?;
let before = other_pool.statistics();
let BytePoolResumeOutcome::Unavailable { retained: token } = other_pool.resume(token) else {
return Err(proptest::test_runner::TestCaseError::fail("foreign owner accepted"));
};
prop_assert_eq!(other_pool.statistics(), before);
*held = Some((token, size, value));
}
(0, Some(owned)) => *held = Some(owned),
(1..=4, None) => {},
(5.., _) => return Err(proptest::test_runner::TestCaseError::fail("invalid test action")),
}
for (pool, held) in pools.iter_mut().zip(&retained) {
let state = pool.statistics();
let owned = held.as_ref().map_or(0, |(_, count, _)| *count);
prop_assert_eq!(state.free_byte_capacity.checked_add(owned), Some(16));
prop_assert_eq!(state.active_lease_count, usize::from(held.is_some()));
}
}
}
}
#[test]
fn inconsistent_resumption_returns_the_identity_with_the_refused_owner() -> Result<(), &'static str>
{
let mut pool = BytePool::try_new(nonzero(8)?, NonZeroUsize::MIN).map_err(|_| "pool")?;
let BytePoolLeaseOutcome::Leased(lease) = pool.lease(nonzero(8)?) else {
return Err("lease");
};
let mut retained = lease.retain();
let address = retained.identity.as_ptr();
retained.range.end = 9;
pool.leases.first_mut().ok_or("slot")?.range.end = 9;
let BytePoolResumeOutcome::Inconsistent {
mut retained,
reason,
} = pool.resume(retained)
else {
return Err("inconsistent region did not preserve ownership");
};
assert_eq!(
reason,
super::BytePoolInconsistency::StorageUnavailable { start: 0, end: 9 }
);
assert_eq!(retained.identity.as_ptr(), address);
retained.range.end = 8;
pool.leases.first_mut().ok_or("slot")?.range.end = 8;
let BytePoolResumeOutcome::Resumed(lease) = pool.resume(retained) else {
return Err("repaired region lost its identity");
};
let retained = lease.retain();
assert_eq!(retained.identity.as_ptr(), address);
assert_eq!(pool.recycle(retained), BytePoolRecycleOutcome::Recycled);
Ok(())
}