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(())
}