diff options
Diffstat (limited to 'ecs/src/component/storage.rs')
-rw-r--r-- | ecs/src/component/storage.rs | 93 |
1 files changed, 61 insertions, 32 deletions
diff --git a/ecs/src/component/storage.rs b/ecs/src/component/storage.rs index 70981a3..76701ac 100644 --- a/ecs/src/component/storage.rs +++ b/ecs/src/component/storage.rs @@ -3,7 +3,12 @@ use std::collections::{HashMap, HashSet}; use std::slice::Iter as SliceIter; use crate::archetype::Id as ArchetypeId; -use crate::component::{Component, Id as ComponentId, IsOptional as ComponentIsOptional}; +use crate::component::{ + Component, + Id as ComponentId, + IsOptional as ComponentIsOptional, + Metadata as ComponentMetadata, +}; use crate::lock::Lock; use crate::type_name::TypeName; use crate::EntityComponent; @@ -13,28 +18,18 @@ pub struct Storage { archetypes: Vec<Archetype>, archetype_lookup: HashMap<ArchetypeId, Vec<usize>>, - pending_archetype_lookup_entries: Vec<Vec<ComponentId>>, + pending_archetype_lookup_entries: Vec<Vec<ComponentMetadata>>, } impl Storage { pub fn find_entities( &self, - component_ids: &[(ComponentId, ComponentIsOptional)], + components_metadata: impl IntoIterator<Item = ComponentMetadata>, ) -> ArchetypeRefIter<'_> { - let ids = component_ids - .iter() - .filter_map(|(component_id, is_optional)| { - if *is_optional == ComponentIsOptional::Yes { - return None; - } - - Some(*component_id) - }); - self.archetype_lookup - .get(&ArchetypeId::new(ids)) + .get(&ArchetypeId::from_components_metadata(components_metadata)) .map_or_else(ArchetypeRefIter::new_empty, |archetypes_indices| { ArchetypeRefIter { inner: archetypes_indices.iter(), @@ -58,11 +53,10 @@ impl Storage let archetype_indices = self .archetype_lookup - .entry(ArchetypeId::new( + .entry(ArchetypeId::from_components_metadata( components .iter() - .filter(|component| !component.is_optional()) - .map(|component| component.id()), + .map(|component| ComponentMetadata::of(&**component)), )) .or_insert_with(|| { self.archetypes.push(Archetype::new( @@ -102,10 +96,13 @@ impl Storage ); } - pub fn add_archetype_lookup_entry(&mut self, component_ids: &[ComponentId]) + pub fn add_archetype_lookup_entry( + &mut self, + components_metadata: impl IntoIterator<Item = ComponentMetadata>, + ) { self.pending_archetype_lookup_entries - .push(component_ids.to_vec()); + .push(components_metadata.into_iter().collect()); } pub fn make_archetype_lookup_entries(&mut self) @@ -115,14 +112,22 @@ impl Storage self.archetype_lookup.clear(); for pending_entry in self.pending_archetype_lookup_entries.drain(..) { - let components_set: HashSet<_> = pending_entry.iter().copied().collect(); + let ids = pending_entry.iter().filter_map(|component_metadata| { + if component_metadata.is_optional == ComponentIsOptional::Yes { + return None; + } + + Some(component_metadata.id) + }); + + let ids_set: HashSet<_> = ids.collect(); let matching_archetype_indices = self .archetypes .iter() .enumerate() .filter_map(|(index, archetype)| { - if archetype.component_ids.is_superset(&components_set) { + if archetype.component_ids.is_superset(&ids_set) { return Some(index); } @@ -131,7 +136,9 @@ impl Storage let archetype_indices = self .archetype_lookup - .entry(ArchetypeId::new(pending_entry.into_iter())) + .entry(ArchetypeId::from_components_metadata( + pending_entry.into_iter(), + )) .or_default(); archetype_indices.extend(matching_archetype_indices); @@ -205,7 +212,11 @@ mod tests use super::{Archetype, Storage}; use crate::archetype::Id as ArchetypeId; - use crate::component::Id as ComponentId; + use crate::component::{ + Id as ComponentId, + IsOptional as ComponentIsOptional, + Metadata as ComponentMetadata, + }; use crate::lock::Lock; use crate::{self as ecs, EntityComponent}; @@ -269,9 +280,15 @@ mod tests let lookup = component_storage .archetype_lookup - .get(&ArchetypeId::new([ - ComponentId::of::<HealthPotion>(), - ComponentId::of::<Hookshot>(), + .get(&ArchetypeId::from_components_metadata([ + ComponentMetadata { + id: ComponentId::of::<HealthPotion>(), + is_optional: ComponentIsOptional::No, + }, + ComponentMetadata { + id: ComponentId::of::<Hookshot>(), + is_optional: ComponentIsOptional::No, + }, ])) .expect("Expected entry in archetype lookup map"); @@ -343,9 +360,15 @@ mod tests ], }); - component_storage.add_archetype_lookup_entry(&[ - ComponentId::of::<IronBoots>(), - ComponentId::of::<Hookshot>(), + component_storage.add_archetype_lookup_entry([ + ComponentMetadata { + id: ComponentId::of::<IronBoots>(), + is_optional: ComponentIsOptional::No, + }, + ComponentMetadata { + id: ComponentId::of::<Hookshot>(), + is_optional: ComponentIsOptional::No, + }, ]); assert_eq!(component_storage.pending_archetype_lookup_entries.len(), 1); @@ -356,9 +379,15 @@ mod tests let archetypes = component_storage .archetype_lookup - .get(&ArchetypeId::new([ - ComponentId::of::<IronBoots>(), - ComponentId::of::<Hookshot>(), + .get(&ArchetypeId::from_components_metadata([ + ComponentMetadata { + id: ComponentId::of::<IronBoots>(), + is_optional: ComponentIsOptional::No, + }, + ComponentMetadata { + id: ComponentId::of::<Hookshot>(), + is_optional: ComponentIsOptional::No, + }, ])) .expect(concat!( "Expected a archetype for IronBoots & Hookshot to be found in the ", |