diff options
Diffstat (limited to 'ecs/src/component')
| -rw-r--r-- | ecs/src/component/local.rs | 75 | ||||
| -rw-r--r-- | ecs/src/component/storage.rs | 86 | ||||
| -rw-r--r-- | ecs/src/component/storage/archetype.rs | 85 | ||||
| -rw-r--r-- | ecs/src/component/storage/graph.rs | 2 |
4 files changed, 129 insertions, 119 deletions
diff --git a/ecs/src/component/local.rs b/ecs/src/component/local.rs index 0f6f641..b19a30b 100644 --- a/ecs/src/component/local.rs +++ b/ecs/src/component/local.rs @@ -1,7 +1,17 @@ +use std::any::type_name; use std::ops::{Deref, DerefMut}; -use crate::component::{Component, HandleMut as ComponentHandleMut}; -use crate::system::{Param as SystemParam, System}; +use ecs_macros::Component; + +use crate::component::{ + Component, + HandleMut as ComponentHandleMut, + IntoParts as _, + Parts as ComponentParts, +}; +use crate::pair::Pair; +use crate::system::initializable::Param as InitializableParam; +use crate::system::{Metadata as SystemMetadata, Param as SystemParam}; use crate::World; /// Holds a component which is local to a single system. @@ -17,27 +27,52 @@ where { type Input = LocalComponent; - fn initialize<SystemImpl>( - system: &mut impl System<'world, SystemImpl>, - input: Self::Input, - ) + fn new(world: &'world World, system_metadata: &SystemMetadata) -> Self { - system.set_local_component(input); - } + let Some(system_ent) = world.get_entity(system_metadata.ent_id) else { + panic!( + "System entity with ID {} does not exist", + system_metadata.ent_id + ); + }; - fn new<SystemImpl>( - system: &'world impl System<'world, SystemImpl>, - _world: &'world World, - ) -> Self - { - let local_component = system - .get_local_component_mut::<LocalComponent>() - .expect("Local component is uninitialized"); + let Some(local_component) = system_ent.get_with_id_mut::<LocalComponent>( + Pair::builder() + .relation::<IsLocalComponent>() + .target::<LocalComponent>() + .build() + .id(), + ) else { + panic!( + "Local component {} of system with ID {} is uninitialized", + type_name::<LocalComponent>(), + system_metadata.ent_id + ); + }; Self { local_component } } } +impl<'world, LocalComponent, SystemT> InitializableParam<'world, SystemT> + for Local<'world, LocalComponent> +where + LocalComponent: Component, + SystemT: SystemWithLocalComponents, + Self: SystemParam<'world, Input = LocalComponent>, +{ + fn initialize(system: &mut SystemT, input: Self::Input) + { + system.add_local_component( + Pair::builder() + .relation::<IsLocalComponent>() + .target_as_data(input) + .build() + .into_parts(), + ); + } +} + impl<LocalComponent> Deref for Local<'_, LocalComponent> where LocalComponent: Component, @@ -59,3 +94,11 @@ where &mut self.local_component } } + +pub trait SystemWithLocalComponents +{ + fn add_local_component(&mut self, component_parts: ComponentParts); +} + +#[derive(Component)] +struct IsLocalComponent; diff --git a/ecs/src/component/storage.rs b/ecs/src/component/storage.rs index 14f3ea4..a8711c5 100644 --- a/ecs/src/component/storage.rs +++ b/ecs/src/component/storage.rs @@ -88,7 +88,7 @@ impl Storage search_terms: ArchetypeSearchTerms<'search_terms>, ) -> ArchetypeRefIter<'_, 'search_terms> { - let archetype_id = ArchetypeId::new(&search_terms.required_components); + let archetype_id = ArchetypeId::new(search_terms.required_components); if search_terms.contains_conflicting() { return ArchetypeRefIter { @@ -105,7 +105,12 @@ impl Storage self.imaginary_archetypes .borrow_mut() .push(ImaginaryArchetype { - id: archetype_id, + id: ArchetypeId::new(search_terms.required_components.iter().filter( + |required_comp_id| { + required_comp_id.kind() != UidKind::Pair + || required_comp_id.target_component() != Uid::wildcard() + }, + )), component_ids: search_terms .required_components .iter() @@ -148,7 +153,7 @@ impl Storage return Err(Error::EntityAlreadyExists(uid)); } - let empty_archetype_id = ArchetypeId::from_components_metadata(&[]); + let empty_archetype_id = ArchetypeId::new_empty(); let archetype_node = self.graph.get_or_create_node(empty_archetype_id, &[]); @@ -216,38 +221,35 @@ impl Storage }); } - let add_edge_archetype_id = match archetype_node + let add_edge_archetype_id = if let Some(add_edge_id) = archetype_node .get_or_insert_edges(component_id, ArchetypeEdges::default) .add { - Some(add_edge_id) => { - if !self.graph.contains_archetype(add_edge_id) { - let (_, add_edge_comp_ids) = self - .graph - .get_node_by_id(archetype_id) - .expect("Archetype should exist") - .make_add_edge(component_id); - - self.graph.create_node(add_edge_id, &add_edge_comp_ids); - } - - add_edge_id - } - None => { - let archetype_node = self + if !self.graph.contains_archetype(add_edge_id) { + let (_, add_edge_comp_ids) = self .graph .get_node_by_id(archetype_id) - .expect("Archetype should exist"); + .expect("Archetype should exist") + .make_add_edge(component_id); - let (add_edge_id, add_edge_comp_ids) = - archetype_node.make_add_edge(component_id); + self.graph.create_node(add_edge_id, &add_edge_comp_ids); + } - if !self.graph.contains_archetype(add_edge_id) { - self.graph.create_node(add_edge_id, &add_edge_comp_ids); - } + add_edge_id + } else { + let archetype_node = self + .graph + .get_node_by_id(archetype_id) + .expect("Archetype should exist"); - add_edge_id + let (add_edge_id, add_edge_comp_ids) = + archetype_node.make_add_edge(component_id); + + if !self.graph.contains_archetype(add_edge_id) { + self.graph.create_node(add_edge_id, &add_edge_comp_ids); } + + add_edge_id }; let archetype_node = self @@ -268,7 +270,7 @@ impl Storage entity.insert_component( component_id, - ArchetypeEntityComponent::new(component, component_id, component_name), + ArchetypeEntityComponent::new(component, component_name), add_edge_archetype, ); @@ -369,9 +371,12 @@ impl Storage ) -> Vec<ArchetypeId> { let Some(mut search_iter) = - self.graph.dfs_archetype_add_edges(ArchetypeId::new(&[])) + self.graph.dfs_archetype_add_edges(ArchetypeId::new_empty()) else { // If the root archetype doesn't exist, no other archetype can exist either + // + // TODO: The above comment is not true. Cases where imaginary archetypes have + // been created should be handled as well return Vec::new(); }; @@ -592,8 +597,7 @@ pub struct ArchetypeRefIter<'storage, 'search_terms> search_terms: ArchetypeSearchTerms<'search_terms>, } -impl<'component_storage, 'search_terms> Iterator - for ArchetypeRefIter<'component_storage, 'search_terms> +impl<'component_storage> Iterator for ArchetypeRefIter<'component_storage, '_> { type Item = &'component_storage Archetype; @@ -638,18 +642,15 @@ impl<'component_storage, 'search_terms> Iterator let mut add_edge_archetype_comps = archetype.component_ids_sorted().collect::<Vec<_>>(); - add_edge_archetype_comps.insert_at_partition_point_by_key( - add_edge_component_id, - |comp_id| *comp_id, - ); + add_edge_archetype_comps + .insert_at_part_pt_by_key(add_edge_component_id, |comp_id| { + comp_id + }); self.storage.imaginary_archetypes.borrow_mut().push( ImaginaryArchetype { id: add_edge_archetype_id, - component_ids: add_edge_archetype_comps - .iter() - .map(|comp_id| *comp_id) - .collect::<Vec<_>>(), + component_ids: add_edge_archetype_comps.clone(), }, ); @@ -663,8 +664,6 @@ impl<'component_storage, 'search_terms> Iterator )), found.into_iter(), )); - - continue; } _ => { unreachable!(); @@ -713,8 +712,7 @@ impl ArchetypeRefIter<'_, '_> let mut add_edge_comp_ids = imaginary_archetype_comps.to_vec(); - add_edge_comp_ids - .insert_at_partition_point_by_key(unique_comp_id, |id| *id); + add_edge_comp_ids.insert_at_part_pt_by_key(unique_comp_id, |id| id); let add_edge = ArchetypeId::new(&add_edge_comp_ids); @@ -774,7 +772,7 @@ mod tests let archetype_node = new_storage .graph - .get_node_by_id(ArchetypeId::from_components_metadata(&[])) + .get_node_by_id(ArchetypeId::new_empty()) .expect("Archetype for entities with no component doesn't exist"); assert_eq!(archetype_node.archetype().component_cnt(), 0); @@ -782,7 +780,7 @@ mod tests assert_eq!( new_storage.entity_archetype_lookup.get(&uid).copied(), - Some(ArchetypeId::from_components_metadata(&[])) + Some(ArchetypeId::new_empty()) ); } } diff --git a/ecs/src/component/storage/archetype.rs b/ecs/src/component/storage/archetype.rs index f8c204b..d96632e 100644 --- a/ecs/src/component/storage/archetype.rs +++ b/ecs/src/component/storage/archetype.rs @@ -7,7 +7,6 @@ use std::slice::Iter as SliceIter; use hashbrown::HashMap; -use crate::component::Metadata as ComponentMetadata; use crate::lock::Lock; use crate::uid::{Kind as UidKind, Uid}; use crate::util::{Either, HashMapExt}; @@ -123,7 +122,7 @@ impl Archetype pub fn get_matching_component_indices( &self, component_id: Uid, - ) -> MatchingComponentIter + ) -> MatchingComponentIter<'_> { assert!( component_id.kind() == UidKind::Component @@ -155,7 +154,7 @@ impl Archetype inner: Either::B( [component_id] .into_iter() - .zip(self.get_index_for_component(component_id).into_iter()), + .zip(self.get_index_for_component(component_id)), ), } } @@ -219,19 +218,20 @@ type MatchingComponentIterFilterFn = fn(&((usize, &Uid), Uid)) -> bool; type MatchingComponentIterMapFn = fn(((usize, &Uid), Uid)) -> (Uid, usize); +type InnerMatchingComponentIterA<'archetype> = Map< + Filter< + Zip<Enumerate<SliceIter<'archetype, Uid>>, RepeatN<Uid>>, + MatchingComponentIterFilterFn, + >, + MatchingComponentIterMapFn, +>; + +type InnerMatchingComponentIterB = Zip<ArrayIntoIter<Uid, 1>, OptionIntoIter<usize>>; + #[derive(Debug)] pub struct MatchingComponentIter<'archetype> { - inner: Either< - Map< - Filter< - Zip<Enumerate<SliceIter<'archetype, Uid>>, RepeatN<Uid>>, - MatchingComponentIterFilterFn, - >, - MatchingComponentIterMapFn, - >, - Zip<ArrayIntoIter<Uid, 1>, OptionIntoIter<usize>>, - >, + inner: Either<InnerMatchingComponentIterA<'archetype>, InnerMatchingComponentIterB>, } impl Iterator for MatchingComponentIter<'_> @@ -314,29 +314,18 @@ impl Entity #[derive(Debug)] pub struct EntityComponent { - id: Uid, component: Lock<Box<dyn Any>>, } impl EntityComponent { - pub fn new( - component: Box<dyn Any>, - component_id: Uid, - component_name: &'static str, - ) -> Self + pub fn new(component: Box<dyn Any>, component_name: &'static str) -> Self { Self { - id: component_id, component: Lock::new(component, component_name), } } - pub fn id(&self) -> Uid - { - self.id - } - pub fn component(&self) -> &Lock<Box<dyn Any>> { &self.component @@ -352,52 +341,32 @@ pub struct Id impl Id { - pub fn new(component_ids: &impl AsRef<[Uid]>) -> Self + pub fn new_empty() -> Self { - if component_ids.as_ref().is_empty() { - return Self { hash: 0 }; - } - - debug_assert!( - component_ids.as_ref().is_sorted(), - "Cannot create archetype ID from unsorted component IDs" - ); - - let mut hasher = DefaultHasher::new(); - - for component_id in component_ids.as_ref() { - component_id.hash(&mut hasher); - } - - Self { hash: hasher.finish() } + Self { hash: 0 } } - pub fn from_components_metadata<'a>( - components_metadata: impl IntoIterator<Item = &'a ComponentMetadata>, - ) -> Self + pub fn new<'a>(component_ids: impl IntoIterator<Item = &'a Uid>) -> Self { let mut hasher = DefaultHasher::new(); let mut prev_component_id: Option<Uid> = None; - let mut comp_metadata_iter = components_metadata.into_iter().peekable(); + let mut component_id_iter = component_ids.into_iter().peekable(); - if comp_metadata_iter.peek().is_none() { - return Self { hash: 0 }; + if component_id_iter.peek().is_none() { + return Self::new_empty(); } - for comp_metadata in comp_metadata_iter { - if prev_component_id - .is_some_and(|prev_comp_id| comp_metadata.id < prev_comp_id) - { - panic!( - "Cannot create archetype ID from a unsorted component metadata list" - ); - } + for comp_id in component_id_iter { + assert!( + prev_component_id.is_none_or(|prev_comp_id| *comp_id >= prev_comp_id), + "Cannot create archetype ID from a unsorted component metadata list" + ); - prev_component_id = Some(comp_metadata.id); + prev_component_id = Some(*comp_id); - comp_metadata.id.hash(&mut hasher); + comp_id.hash(&mut hasher); } Self { hash: hasher.finish() } diff --git a/ecs/src/component/storage/graph.rs b/ecs/src/component/storage/graph.rs index 29fa937..76200f9 100644 --- a/ecs/src/component/storage/graph.rs +++ b/ecs/src/component/storage/graph.rs @@ -80,7 +80,7 @@ impl Graph pub fn dfs_archetype_add_edges( &self, archetype_id: ArchetypeId, - ) -> Option<ArchetypeAddEdgeDfsIter> + ) -> Option<ArchetypeAddEdgeDfsIter<'_>> { let node = self.get_node_by_id(archetype_id)?; |
