#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub struct EntityId {
index: u32,
generation: u32,
}
impl EntityId {
pub const fn new(index: u32, generation: u32) -> Self {
Self { index, generation }
}
#[inline(always)]
pub fn index(self) -> u32 {
self.index
}
#[inline(always)]
pub fn generation(self) -> u32 {
self.generation
}
}
#[derive(Debug, Clone, Copy)]
pub(crate) struct EntityLocation {
pub data_index: usize,
pub chunk_index: usize,
pub entity_index: usize,
}
#[derive(Debug, Clone, Copy)]
pub(crate) struct EntityRecord {
pub generation: u32,
data_index: u32,
chunk_index: u32,
entity_index: u32,
}
impl EntityRecord {
const VACANT_DATA_INDEX: u32 = u32::MAX;
#[inline(always)]
pub(crate) fn vacant(generation: u32) -> Self {
Self {
generation,
data_index: Self::VACANT_DATA_INDEX,
chunk_index: 0,
entity_index: 0,
}
}
#[inline(always)]
pub(crate) fn location(self) -> Option<EntityLocation> {
if self.data_index == Self::VACANT_DATA_INDEX {
return None;
}
Some(EntityLocation {
data_index: self.data_index as usize,
chunk_index: self.chunk_index as usize,
entity_index: self.entity_index as usize,
})
}
#[inline(always)]
pub(crate) fn set_location(&mut self, location: EntityLocation) {
self.data_index = u32::try_from(location.data_index)
.ok()
.filter(|&index| index != Self::VACANT_DATA_INDEX)
.expect("World storage index limit exhausted");
self.chunk_index =
u32::try_from(location.chunk_index).expect("chunk index limit exhausted");
self.entity_index =
u32::try_from(location.entity_index).expect("chunk entity index limit exhausted");
}
#[inline(always)]
pub(crate) fn clear_location(&mut self) {
self.data_index = Self::VACANT_DATA_INDEX;
}
#[inline(always)]
pub(crate) fn is_alive(self) -> bool {
self.data_index != Self::VACANT_DATA_INDEX
}
}
#[cfg(test)]
mod tests {
use super::{EntityLocation, EntityRecord};
#[test]
fn entity_record_stays_cache_dense() {
assert_eq!(std::mem::size_of::<EntityRecord>(), 16);
let mut record = EntityRecord::vacant(7);
assert!(!record.is_alive());
assert!(record.location().is_none());
let location = EntityLocation {
data_index: 3,
chunk_index: 5,
entity_index: 8,
};
record.set_location(location);
assert!(record.is_alive());
let actual = record.location().unwrap();
assert_eq!(actual.data_index, location.data_index);
assert_eq!(actual.chunk_index, location.chunk_index);
assert_eq!(actual.entity_index, location.entity_index);
record.clear_location();
assert!(!record.is_alive());
assert!(record.location().is_none());
}
}