#![deny(clippy::all, clippy::pedantic)] use std::any::TypeId; use std::collections::{HashMap, HashSet}; use std::fmt::Debug; use std::hash::Hash; use std::marker::PhantomData; use std::slice::IterMut as SliceIterMut; use crate::component::{Component, Sequence as ComponentSequence}; pub mod component; #[derive(Debug)] struct Entity { components: Vec>, } #[derive(Debug)] pub struct World { systems: Vec>, events: HashMap>, extra: WorldExtra, } #[derive(Debug)] struct WorldExtra { entities: Vec, } impl World { #[must_use] pub fn new() -> Self { Self { systems: Vec::new(), extra: WorldExtra { entities: Vec::new() }, events: HashMap::new(), } } pub fn create_entity(&mut self, components: Comps) where Comps: ComponentSequence, { self.extra .entities .push(Entity { components: components.into_vec() }); } pub fn register_system(&mut self, event: Event, system: System) where Event: Hash + PartialEq + Eq, Comps: ComponentSequence + 'static, { self.systems.push(Box::new(system)); self.events .entry(event) .or_default() .push(self.systems.len() - 1); } /// Emits a event, running all systems listening to the event for each compatible /// entity. /// /// # Panics /// Will panic if a system has dissapeared. pub fn emit(&mut self, event: &Event) where Event: Hash + PartialEq + Eq, { let Some(system_indices) = self.events.get(event).cloned() else { return; }; for system_index in system_indices { let system = self.systems.get_mut(system_index).unwrap(); system.call(&mut self.extra); } } pub fn query(&mut self) -> Query where Comps: ComponentSequence, { Query::new(&mut self.extra) } } impl Default for World { fn default() -> Self { Self::new() } } pub type System = fn(Query); trait AnySystem { fn call(&self, world: &mut WorldExtra); } impl AnySystem for System where Comps: ComponentSequence, { fn call(&self, world: &mut WorldExtra) { self(Query::new(world)); } } impl Debug for dyn AnySystem { fn fmt(&self, formatter: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { formatter.debug_struct("AnySystem").finish_non_exhaustive() } } #[derive(Debug)] pub struct Query<'world, Comps> { world: &'world mut WorldExtra, comps_pd: PhantomData, } impl<'world, Comps> Query<'world, Comps> { fn new(world: &'world mut WorldExtra) -> Self { Self { world, comps_pd: PhantomData } } } impl<'world, Comps> Query<'world, Comps> where Comps: ComponentSequence, { pub fn iter_mut(&mut self) -> QueryComponentIter { QueryComponentIter { entity_iter: self.world.entities.iter_mut(), component_type_ids: Comps::type_ids(), comps_pd: PhantomData, } } } pub struct QueryComponentIter<'world, Comps> { entity_iter: SliceIterMut<'world, Entity>, component_type_ids: Vec, comps_pd: PhantomData, } impl<'world, Comps> Iterator for QueryComponentIter<'world, Comps> where Comps: ComponentSequence + 'world, { type Item = Comps::MutRefs<'world>; fn next(&mut self) -> Option { // TODO: This is a really dumb and slow way to do this. Refactor the world // to store components in archetypes let entity = self.entity_iter.find(|entity| { let entity_components: HashSet<_> = entity .components .iter() .map(|component| component.as_ref().type_id()) .collect(); if self.component_type_ids.iter().all(|component_type_id| { entity_components.contains(component_type_id) }) { return true; } false })?; Some(Comps::from_components(&mut entity.components)) } }