use concinnity_core::render::draw_slot::{DrawSlotAllocator, SlotAlloc};
use concinnity_core::render::skinned_pool::SkinnedInstancePool;
pub(crate) struct RenderSlots {
draws: DrawSlotAllocator,
skinned: SkinnedInstancePool,
reuse_floor: usize,
}
impl RenderSlots {
pub(crate) fn new(
build_draw_count: usize,
reuses_build_slots: bool,
skinned_reservations: &[(usize, usize)],
) -> Self {
let mut skinned = SkinnedInstancePool::new();
for &(template, instance) in skinned_reservations {
skinned.reserve(template, instance);
}
Self {
draws: DrawSlotAllocator::with_len(build_draw_count),
skinned,
reuse_floor: if reuses_build_slots {
0
} else {
build_draw_count
},
}
}
pub(crate) fn allocate_draw(&mut self) -> SlotAlloc {
self.draws.allocate()
}
pub(crate) fn free_draw(&mut self, slot: usize) {
if slot >= self.reuse_floor {
self.draws.free(slot);
}
}
pub(crate) fn claim_skinned(&mut self, template: usize) -> Option<usize> {
self.skinned.acquire(template)
}
pub(crate) fn release_skinned(&mut self, instance: usize) -> bool {
self.skinned.release(instance)
}
pub(crate) fn skinned_free(&self) -> usize {
self.skinned.total_free()
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn build_slots_recycle_only_above_the_floor() {
let mut slots = RenderSlots::new(4, false, &[]);
slots.free_draw(2);
assert_eq!(
slots.allocate_draw(),
SlotAlloc::Append(4),
"a freed build-time slot is not recycled"
);
slots.free_draw(4);
assert_eq!(
slots.allocate_draw(),
SlotAlloc::Reuse(4),
"a runtime-append slot is recycled"
);
}
#[test]
fn build_slots_recycle_everywhere_without_the_floor() {
let mut slots = RenderSlots::new(4, true, &[]);
slots.free_draw(2);
assert_eq!(slots.allocate_draw(), SlotAlloc::Reuse(2));
}
#[test]
fn skinned_pool_claims_and_releases_per_template() {
let mut slots = RenderSlots::new(0, true, &[(0, 5), (0, 6), (3, 9)]);
assert_eq!(slots.skinned_free(), 3);
let a = slots.claim_skinned(0).expect("first copy");
let b = slots.claim_skinned(0).expect("second copy");
assert!(slots.claim_skinned(0).is_none(), "reserve exhausted");
assert!(slots.release_skinned(a));
assert_eq!(slots.claim_skinned(0), Some(a), "released slot recycles");
assert!(
!slots.release_skinned(42),
"unknown slot is not a pool slot"
);
let _ = b;
assert_eq!(slots.claim_skinned(3), Some(9));
}
}