use crate::object::EntityId;
#[derive(Clone, Debug)]
pub struct EntityMeta {
pub offset: u32,
pub len: u32,
pub save_level: u16,
pub flags: u8,
pub created_after_save: u32,
}
impl EntityMeta {
const FLAG_GLOBAL: u8 = 1;
pub fn is_global(&self) -> bool {
self.flags & Self::FLAG_GLOBAL != 0
}
pub fn set_global(&mut self, global: bool) {
if global {
self.flags |= Self::FLAG_GLOBAL;
} else {
self.flags &= !Self::FLAG_GLOBAL;
}
}
}
pub struct EntityTable {
entries: Vec<EntityMeta>,
}
impl EntityTable {
pub fn new() -> Self {
Self {
entries: Vec::new(),
}
}
pub fn allocate(
&mut self,
offset: u32,
len: u32,
save_level: u16,
global: bool,
created_after_save: u32,
) -> EntityId {
let index = self.entries.len() as u32;
let id = if global {
EntityId::global(index)
} else {
EntityId::local(index)
};
let mut flags = 0u8;
if global {
flags |= EntityMeta::FLAG_GLOBAL;
}
self.entries.push(EntityMeta {
offset,
len,
save_level,
flags,
created_after_save,
});
id
}
#[inline]
pub fn get(&self, id: EntityId) -> &EntityMeta {
&self.entries[id.raw_index()]
}
pub fn get_mut(&mut self, id: EntityId) -> &mut EntityMeta {
&mut self.entries[id.raw_index()]
}
pub fn len(&self) -> usize {
self.entries.len()
}
pub fn is_empty(&self) -> bool {
self.entries.is_empty()
}
}
impl Default for EntityTable {
fn default() -> Self {
Self::new()
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_allocate_and_get() {
let mut table = EntityTable::new();
let id = table.allocate(0, 10, 0, false, 0);
assert_eq!(id, EntityId::local(0));
assert!(!id.is_global());
let meta = table.get(id);
assert_eq!(meta.offset, 0);
assert_eq!(meta.len, 10);
assert_eq!(meta.save_level, 0);
assert!(!meta.is_global());
}
#[test]
fn test_multiple_allocations() {
let mut table = EntityTable::new();
let id0 = table.allocate(0, 5, 0, false, 0);
let id1 = table.allocate(5, 10, 0, true, 0);
assert_eq!(id0, EntityId::local(0));
assert_eq!(id1, EntityId::global(1));
assert_eq!(table.len(), 2);
assert!(!id0.is_global());
assert!(id1.is_global());
}
#[test]
fn test_get_mut() {
let mut table = EntityTable::new();
let id = table.allocate(0, 5, 0, false, 0);
table.get_mut(id).offset = 100;
assert_eq!(table.get(id).offset, 100);
}
#[test]
fn test_global_flag() {
let mut table = EntityTable::new();
let id = table.allocate(0, 5, 0, false, 0);
assert!(!table.get(id).is_global());
table.get_mut(id).set_global(true);
assert!(table.get(id).is_global());
table.get_mut(id).set_global(false);
assert!(!table.get(id).is_global());
}
#[test]
fn test_save_level_tracking() {
let mut table = EntityTable::new();
let id = table.allocate(0, 5, 1, false, 0);
assert_eq!(table.get(id).save_level, 1);
table.get_mut(id).save_level = 2;
assert_eq!(table.get(id).save_level, 2);
}
#[test]
fn test_empty_table() {
let table = EntityTable::new();
assert_eq!(table.len(), 0);
assert!(table.is_empty());
}
#[test]
fn test_default() {
let table = EntityTable::default();
assert!(table.is_empty());
}
#[test]
fn test_len_after_allocations() {
let mut table = EntityTable::new();
table.allocate(0, 1, 0, false, 0);
table.allocate(1, 2, 0, false, 0);
table.allocate(3, 3, 0, false, 0);
assert_eq!(table.len(), 3);
assert!(!table.is_empty());
}
}