use std::cell::RefCell;
use crate::{component::ComponentId, entity_store::EntityId, layout_vec::LayoutVec};
#[derive(Clone, Copy, Debug, PartialEq, PartialOrd)]
pub struct ArchetypeId(pub u32);
#[derive(Clone, Copy, Debug, PartialEq, PartialOrd)]
pub struct ArchetypeRow(pub u32);
#[derive(Clone, Copy, Debug, PartialEq, PartialOrd)]
pub struct ArchetypeColumn(pub u32);
impl ArchetypeId {
pub fn as_index(&self) -> usize {
self.0 as usize
}
}
impl ArchetypeRow {
pub fn as_index(&self) -> usize {
self.0 as usize
}
}
pub enum Erased {}
pub type ErasedPointer = *const RefCell<Erased>;
pub struct Archetype {
pub components: Vec<ComponentId>,
pub columns: Vec<LayoutVec>,
pub entities: Vec<EntityId>,
}
impl Archetype {
pub fn new(components: Vec<ComponentId>, columns: Vec<LayoutVec>) -> Self {
debug_assert!(components.is_sorted());
debug_assert_eq!(components.len(), columns.len());
Archetype {
components,
columns,
entities: Vec::new(),
}
}
pub fn move_row(old: &mut Self, new: &mut Self, row: ArchetypeRow) {
debug_assert!(new.components.len().abs_diff(old.components.len()) <= 1);
let new_bigger = new.components.len() > old.components.len();
let mut i = 0;
let mut j = 0;
while i < old.components.len() && j < new.components.len() {
if old.components[i] != new.components[j] {
if new_bigger {
j += 1;
} else {
i += 1;
}
debug_assert_eq!(old.components[i], new.components[j]);
}
let from = &mut old.columns[i];
let to = &mut new.columns[j];
unsafe {
LayoutVec::move_entry(from, to, row.0);
}
i += 1;
j += 1;
}
debug_assert!(
i.abs_diff(j) <= 1,
"\nOld: {:?}\nNew: {:?}",
&old.components,
&new.components
);
let e_id = old.entities.swap_remove(row.0 as usize);
new.entities.push(e_id);
}
#[must_use]
pub fn delete_row(&mut self, row: ArchetypeRow) -> bool {
self.entities.swap_remove(row.0 as usize);
for col in &mut self.columns {
col.remove_swap(row.0);
}
row.0 != self.entities.len() as u32
}
pub fn find_column(&self, cid: ComponentId) -> &LayoutVec {
let index = self.components.iter().position(|it| *it == cid).unwrap();
&self.columns[index]
}
pub fn find_column_mut(&mut self, cid: ComponentId) -> &mut LayoutVec {
let index = self.components.iter().position(|it| *it == cid).unwrap();
&mut self.columns[index]
}
pub fn find_column_opt(&self, cid: ComponentId) -> Option<&LayoutVec> {
let index = self.components.iter().position(|it| *it == cid);
index.map(|it| &self.columns[it])
}
fn find_multiple_columns_internal(
&self,
cids: &[ComponentId],
result_indexes: &mut [usize],
) -> usize {
debug_assert_eq!(cids.len(), result_indexes.len());
debug_assert!(cids.is_sorted());
if cids.is_empty() {
return 0;
}
let mut j = 0;
for i in 0..self.components.len() {
if self.components[i] == cids[j] {
result_indexes[j] = i;
j += 1;
if j >= cids.len() {
break;
}
}
}
return j;
}
pub fn find_multiple_columns(&self, cids: &[ComponentId], result_indexes: &mut [usize]) {
let j = self.find_multiple_columns_internal(cids, result_indexes);
debug_assert_eq!(
cids.len(),
j,
"Internal: did not find as many cids as requested."
);
}
pub fn find_multiple_columns_fallible(
&self,
cids: &[ComponentId],
result_indexes: &mut [usize],
) -> bool {
let j = self.find_multiple_columns_internal(cids, result_indexes);
cids.len() == j
}
}
#[cfg(test)]
mod test {
use super::*;
#[test]
fn check_struct_sizes() {
assert!(72 >= size_of::<Archetype>()); }
}