pub trait ContentHandle: Copy + Eq {
const INVALID: Self;
fn index(&self) -> usize;
fn generation(&self) -> u32;
fn from_parts(index: u32, generation: u32) -> Self;
fn is_valid(&self) -> bool {
*self != Self::INVALID
}
}
macro_rules! slot_handle {
($(#[$meta:meta])* $vis:vis struct $name:ident;) => {
$(#[$meta])*
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
$vis struct $name {
pub(crate) index: u32,
pub(crate) generation: u32,
}
impl $name {
pub const INVALID: $name = $name {
index: u32::MAX,
generation: u32::MAX,
};
pub fn index(&self) -> usize {
self.index as usize
}
pub(crate) fn new(index: u32, generation: u32) -> Self {
Self { index, generation }
}
}
impl $crate::resources::handle::ContentHandle for $name {
const INVALID: Self = <$name>::INVALID;
fn index(&self) -> usize {
self.index as usize
}
fn generation(&self) -> u32 {
self.generation
}
fn from_parts(index: u32, generation: u32) -> Self {
<$name>::new(index, generation)
}
}
};
}
pub(crate) use slot_handle;
macro_rules! registry_handle {
($(#[$meta:meta])* $vis:vis struct $name:ident;) => {
$(#[$meta])*
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
$vis struct $name(pub(crate) usize);
impl $name {
pub fn index(&self) -> usize {
self.0
}
}
};
}
pub(crate) use registry_handle;
pub(crate) struct Registry<T> {
items: Vec<T>,
}
impl<T> Registry<T> {
pub(crate) fn push(&mut self, value: T) -> usize {
let index = self.items.len();
self.items.push(value);
index
}
pub(crate) fn get(&self, index: usize) -> Option<&T> {
self.items.get(index)
}
pub(crate) fn get_mut(&mut self, index: usize) -> Option<&mut T> {
self.items.get_mut(index)
}
pub(crate) fn len(&self) -> usize {
self.items.len()
}
}
impl<T> Default for Registry<T> {
fn default() -> Self {
Self { items: Vec::new() }
}
}
struct Slot<T> {
value: Option<T>,
generation: u32,
bytes: u64,
}
pub(crate) struct SlotStore<T, H: ContentHandle> {
slots: Vec<Slot<T>>,
free_list: Vec<usize>,
allocated_bytes: u64,
live_count: usize,
_handle: std::marker::PhantomData<H>,
}
impl<T, H: ContentHandle> SlotStore<T, H> {
pub(crate) fn insert(&mut self, value: T, bytes: u64) -> H {
self.allocated_bytes += bytes;
self.live_count += 1;
if let Some(idx) = self.free_list.pop() {
let slot = &mut self.slots[idx];
slot.value = Some(value);
slot.bytes = bytes;
H::from_parts(idx as u32, slot.generation)
} else {
let idx = self.slots.len();
self.slots.push(Slot {
value: Some(value),
generation: 0,
bytes,
});
H::from_parts(idx as u32, 0)
}
}
fn live_slot(&self, id: H) -> Option<&Slot<T>> {
let slot = self.slots.get(id.index())?;
if slot.generation != id.generation() {
return None;
}
slot.value.is_some().then_some(slot)
}
pub(crate) fn get(&self, id: H) -> Option<&T> {
self.live_slot(id)?.value.as_ref()
}
pub(crate) fn get_mut(&mut self, id: H) -> Option<&mut T> {
let slot = self.slots.get_mut(id.index())?;
if slot.generation != id.generation() {
return None;
}
slot.value.as_mut()
}
pub(crate) fn get_by_index(&self, index: usize) -> Option<&T> {
self.slots.get(index)?.value.as_ref()
}
pub(crate) fn get_mut_by_index(&mut self, index: usize) -> Option<&mut T> {
self.slots.get_mut(index)?.value.as_mut()
}
pub(crate) fn replace(&mut self, id: H, value: T, bytes: u64) -> Option<T> {
let slot = self.slots.get_mut(id.index())?;
if slot.generation != id.generation() || slot.value.is_none() {
return None;
}
let old = slot.value.replace(value);
self.allocated_bytes = self.allocated_bytes.saturating_sub(slot.bytes) + bytes;
slot.bytes = bytes;
old
}
pub(crate) fn remove(&mut self, id: H) -> Option<T> {
let slot = self.slots.get_mut(id.index())?;
if slot.generation != id.generation() {
return None;
}
let value = slot.value.take()?;
self.allocated_bytes = self.allocated_bytes.saturating_sub(slot.bytes);
slot.bytes = 0;
slot.generation = slot.generation.wrapping_add(1);
self.free_list.push(id.index());
self.live_count -= 1;
Some(value)
}
pub(crate) fn contains(&self, id: H) -> bool {
self.live_slot(id).is_some()
}
pub(crate) fn len(&self) -> usize {
self.live_count
}
pub(crate) fn slot_count(&self) -> usize {
self.slots.len()
}
pub(crate) fn allocated_bytes(&self) -> u64 {
self.allocated_bytes
}
pub(crate) fn iter(&self) -> impl Iterator<Item = (H, &T)> {
self.slots.iter().enumerate().filter_map(|(idx, slot)| {
slot.value
.as_ref()
.map(|v| (H::from_parts(idx as u32, slot.generation), v))
})
}
pub(crate) fn iter_mut(&mut self) -> impl Iterator<Item = (H, &mut T)> {
self.slots.iter_mut().enumerate().filter_map(|(idx, slot)| {
let generation = slot.generation;
slot.value
.as_mut()
.map(|v| (H::from_parts(idx as u32, generation), v))
})
}
}
impl<T, H: ContentHandle> Default for SlotStore<T, H> {
fn default() -> Self {
Self {
slots: Vec::new(),
free_list: Vec::new(),
allocated_bytes: 0,
live_count: 0,
_handle: std::marker::PhantomData,
}
}
}