use crate::engine::types::{ArchetypeID, ComponentID, COMPONENT_CAP};
use crate::engine::storage::{LockedAttribute, TypeErasedAttribute};
use crate::engine::component::{ComponentRegistry, Signature};
use crate::engine::error::{ECSError, ECSResult, InternalViolation, RegistryError, SpawnError};
use super::core::Archetype;
impl Archetype {
#[inline]
pub fn ensure_component(
&mut self,
component_id: ComponentID,
factory: impl FnOnce() -> Result<Box<dyn TypeErasedAttribute>, RegistryError>,
) -> Result<(), SpawnError> {
let index = component_id as usize;
if index >= COMPONENT_CAP {
return Err(SpawnError::InvalidComponentId);
}
match self
.components
.binary_search_by_key(&component_id, |(cid, _)| *cid)
{
Ok(_) => { }
Err(insert_pos) => {
let col = factory()?;
self.components
.insert(insert_pos, (component_id, LockedAttribute::new(col)));
self.signature.set(component_id);
}
}
Ok(())
}
pub fn insert_empty_component(
&mut self,
component_id: ComponentID,
component: Box<dyn TypeErasedAttribute>,
) -> ECSResult<()> {
let index = component_id as usize;
if index >= COMPONENT_CAP {
return Err(SpawnError::InvalidComponentId.into());
}
match self
.components
.binary_search_by_key(&component_id, |(cid, _)| *cid)
{
Ok(_) => {
return Err(InternalViolation::ComponentAlreadyPresent.into());
}
Err(insert_pos) => {
self.components
.insert(insert_pos, (component_id, LockedAttribute::new(component)));
self.signature.set(component_id);
}
}
Ok(())
}
pub fn remove_component(
&mut self,
component_id: ComponentID,
) -> ECSResult<Option<Box<dyn TypeErasedAttribute>>> {
if self.length()? > 0 {
return Err(SpawnError::ArchetypeNotEmpty.into());
}
let index = component_id as usize;
if index >= COMPONENT_CAP {
return Err(SpawnError::InvalidComponentId.into());
}
match self
.components
.binary_search_by_key(&component_id, |(cid, _)| *cid)
{
Ok(pos) => {
let (_, locked) = self.components.remove(pos);
self.signature.clear(component_id);
Ok(Some(
locked
.into_inner()
.map_err(SpawnError::StoragePushFailedWith)?,
))
}
Err(_) => Ok(None),
}
}
pub fn from_components<T: IntoIterator<Item = std::any::TypeId>>(
archetype_id: ArchetypeID,
types: T,
registry: &ComponentRegistry,
) -> ECSResult<Self> {
let mut signature = Signature::default();
let mut component_ids = Vec::new();
for type_id in types {
let component_id = registry
.component_id_of_type_id(type_id)
.ok_or(ECSError::from(
InternalViolation::ComponentTypeNotRegistered,
))?;
signature.set(component_id);
component_ids.push(component_id);
}
let archetype = Self::new(archetype_id, signature, registry)?;
if !component_ids.iter().all(|&id| archetype.has(id)) {
return Err(InternalViolation::SignatureStorageMismatch.into());
}
Ok(archetype)
}
}