#![deny(clippy::all, clippy::pedantic)] use std::any::{type_name, Any, TypeId}; use std::collections::{HashMap, HashSet}; use std::fmt::Debug; use std::marker::PhantomData; use std::mem::ManuallyDrop; use std::ops::RangeBounds; use std::slice::Iter as SliceIter; use std::sync::{Arc, Weak}; use std::vec::Drain; use crate::actions::Action; use crate::component::{Component, Sequence as ComponentSequence}; use crate::event::{Event, Id as EventId}; use crate::lock::{Lock, ReadGuard}; use crate::system::{ NoInitParamFlag as NoInitSystemParamFlag, Param as SystemParam, System, TypeErased as TypeErasedSystem, }; use crate::tuple::FilterExclude as TupleFilterExclude; use crate::type_name::TypeName; pub mod actions; pub mod component; pub mod event; pub mod lock; pub mod system; pub mod tuple; pub mod type_name; pub use ecs_macros::Component; #[derive(Debug, Default)] struct Entity { components: Vec>, } #[derive(Debug)] struct EntityComponent { id: TypeId, component: Lock>, drop_last: bool, } #[derive(Debug, Default)] pub struct World { systems: Vec, data: WorldData, } impl World { #[must_use] pub fn new() -> Self { Self::default() } pub fn create_entity(&mut self, components: Comps) where Comps: ComponentSequence, { self.data .component_storage .write_nonblock() .expect("Failed to acquire read-write component storage lock") .entities .push(Entity { components: components .into_vec() .into_iter() .map(|component| { let drop_last = component.drop_last(); ManuallyDrop::new(EntityComponent { id: (*component).type_id(), component: Lock::new(component), drop_last, }) }) .collect(), }); } pub fn register_system<'this, SystemImpl>( &'this mut self, event: &impl Event, system: impl System<'this, SystemImpl>, ) { self.systems.push(system.into_type_erased()); self.data .events .entry(event.id()) .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(&self, event: &impl Event) { let Some(system_indices) = self.data.events.get(&event.id()).cloned() else { return; }; for system_index in system_indices { let system = self.systems.get(system_index).unwrap(); // SAFETY: The world data lives long enough unsafe { system.run(&self.data); } } } pub fn query(&self) -> Query where Comps: ComponentSequence, { Query::new(&self.data.component_storage) } /// Peforms the actions that have been queued up using [`Actions`]. pub fn perform_queued_actions(&self) { for action in self .data .action_queue .write_nonblock() .expect("Failed to aquire read-write action queue lock") .drain(..) { match action { Action::Spawn(components) => { self.data .component_storage .write_nonblock() .expect("Failed to acquire read-write component storage lock") .entities .push(Entity { components: components .into_iter() .map(|component| { let drop_last = component.drop_last(); ManuallyDrop::new(EntityComponent { id: (*component).type_id(), component: Lock::new(component), drop_last, }) }) .collect(), }); } } } } } #[derive(Debug, Default)] pub struct WorldData { events: HashMap>, component_storage: Arc>, action_queue: Lock, } #[derive(Debug, Default)] struct ActionQueue { queue: Vec, } impl ActionQueue { fn push(&mut self, action: Action) { self.queue.push(action); } fn drain(&mut self, range: impl RangeBounds) -> Drain { self.queue.drain(range) } } impl TypeName for ActionQueue { fn type_name(&self) -> &'static str { type_name::() } } /// A entity query. #[derive(Debug)] pub struct Query<'world, Comps> where Comps: ComponentSequence, { component_storage: ReadGuard<'world, ComponentStorage>, component_storage_lock: Weak>, comps_pd: PhantomData, } impl<'world, Comps> Query<'world, Comps> where Comps: ComponentSequence, { pub fn iter<'this>(&'this self) -> QueryComponentIter<'world, Comps> where 'this: 'world, { QueryComponentIter { entity_iter: self.component_storage.entities.iter(), component_type_ids: Comps::type_ids(), comps_pd: PhantomData, } } /// Returns a weak reference query to the same components. pub fn to_weak_ref(&self) -> WeakRefQuery { WeakRefQuery { component_storage: self.component_storage_lock.clone(), comps_pd: PhantomData, } } fn new(component_storage: &'world Arc>) -> Self { Self { component_storage: component_storage .read_nonblock() .expect("Failed to acquire read-only component storage lock"), component_storage_lock: Arc::downgrade(component_storage), comps_pd: PhantomData, } } } impl<'world, Comps> IntoIterator for &'world Query<'world, Comps> where Comps: ComponentSequence, { type IntoIter = QueryComponentIter<'world, Comps>; type Item = Comps::Refs<'world>; fn into_iter(self) -> Self::IntoIter { self.iter() } } unsafe impl<'world, Comps> SystemParam<'world> for Query<'world, Comps> where Comps: ComponentSequence, { type Flags = NoInitSystemParamFlag; type Input = TupleFilterExclude; fn initialize( _system: &mut impl System<'world, SystemImpl>, _input: Self::Input, ) { } fn new( _system: &'world impl System<'world, SystemImpl>, world_data: &'world WorldData, ) -> Self { Self::new(&world_data.component_storage) } fn is_compatible>() -> bool { let other_comparable = Other::get_comparable(); let Some(other_query_component_ids) = other_comparable.downcast_ref::() else { return true; }; !other_query_component_ids.contains_component_in::() } fn get_comparable() -> Box { Box::new(QueryComponentIds { component_type_ids: Comps::type_ids(), }) } } /// A entity query containing a weak reference to the world. #[derive(Debug)] pub struct WeakRefQuery where Comps: ComponentSequence, { component_storage: Weak>, comps_pd: PhantomData, } impl WeakRefQuery where Comps: ComponentSequence, { /// Returns a struct which can be used to retrieve a [`Query`]. /// /// Returns [`None`] if the [`World`] has been dropped. pub fn access(&self) -> Option> { Some(RefQuery { component_storage: self.component_storage.upgrade()?, _pd: PhantomData, }) } } impl Clone for WeakRefQuery where Comps: ComponentSequence, { fn clone(&self) -> Self { Self { component_storage: self.component_storage.clone(), comps_pd: PhantomData, } } } /// Intermediate between [`Query`] and [`WeakRefQuery`]. Contains a strong reference to /// the world which is not allowed direct access to. #[derive(Debug, Clone)] pub struct RefQuery<'weak_ref, Comps> where Comps: ComponentSequence, { component_storage: Arc>, _pd: PhantomData<&'weak_ref Comps>, } impl<'weak_ref, Comps> RefQuery<'weak_ref, Comps> where Comps: ComponentSequence, { pub fn to_query(&self) -> Query<'_, Comps> { Query::new(&self.component_storage) } } #[derive(Debug)] struct QueryComponentIds { component_type_ids: Vec, } impl QueryComponentIds { fn contains_component_in(&self) -> bool where OtherComps: ComponentSequence, { let other_component_type_ids = OtherComps::type_ids() .into_iter() .collect::>(); // TODO: Make this a bit smarter. Queries with a same component can be compatible // if one of the queries have a component the other one does not have self.component_type_ids .iter() .any(|component_type_id| other_component_type_ids.contains(component_type_id)) } } pub struct QueryComponentIter<'world, Comps> { entity_iter: SliceIter<'world, Entity>, component_type_ids: Vec, comps_pd: PhantomData, } impl<'world, Comps> Iterator for QueryComponentIter<'world, Comps> where Comps: ComponentSequence + 'world, { type Item = Comps::Refs<'world>; fn next(&mut self) -> Option { let matching_entity = find_entity_with_components(&mut self.entity_iter, &self.component_type_ids)?; Some(Comps::from_components( matching_entity .components .iter() .map(|component| &component.component), )) } } fn find_entity_with_components<'world>( entity_iter: &mut impl Iterator, component_type_ids: &[TypeId], ) -> Option<&'world Entity> { // TODO: This is a really dumb and slow way to do this. Refactor the world // to store components in archetypes entity_iter.find(|entity| { let entity_components = entity .components .iter() .map(|component| component.id) .collect::>(); if component_type_ids .iter() .all(|component_type_id| entity_components.contains(component_type_id)) { return true; } false }) } #[derive(Debug, Default)] pub struct ComponentStorage { entities: Vec, } impl TypeName for ComponentStorage { fn type_name(&self) -> &'static str { type_name::() } } impl Drop for ComponentStorage { fn drop(&mut self) { let mut components_to_drop_last = Vec::new(); for entity in &mut self.entities { for component in &mut entity.components { if component.drop_last { #[cfg(feature = "debug")] tracing::debug!( "Component {} pushed to dropping last queue", component.component.read_nonblock().unwrap().type_name() ); components_to_drop_last.push(component); continue; } #[cfg(feature = "debug")] tracing::debug!( "Dropping component {}", component.component.read_nonblock().unwrap().type_name() ); unsafe { ManuallyDrop::drop(component); } } } for component in &mut components_to_drop_last { #[cfg(feature = "debug")] tracing::debug!( "Dropping component {} last", component.component.read_nonblock().unwrap().type_name() ); unsafe { ManuallyDrop::drop(component); } } } }