summaryrefslogtreecommitdiff
path: root/ecs/src/component/storage.rs
diff options
context:
space:
mode:
Diffstat (limited to 'ecs/src/component/storage.rs')
-rw-r--r--ecs/src/component/storage.rs93
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 ",