summaryrefslogtreecommitdiff
path: root/engine-ecs/src/component/storage.rs
diff options
context:
space:
mode:
Diffstat (limited to 'engine-ecs/src/component/storage.rs')
-rw-r--r--engine-ecs/src/component/storage.rs240
1 files changed, 196 insertions, 44 deletions
diff --git a/engine-ecs/src/component/storage.rs b/engine-ecs/src/component/storage.rs
index a4944c7..4a1c035 100644
--- a/engine-ecs/src/component/storage.rs
+++ b/engine-ecs/src/component/storage.rs
@@ -17,7 +17,8 @@ use crate::component::storage::graph::{
ArchetypeEdges,
Graph,
};
-use crate::uid::Uid;
+use crate::uid::{PairParams, Uid};
+use crate::util::array_vec::ArrayVec;
use crate::util::{BorrowedOrOwned, Either, StreamingIterator, VecExt};
pub mod archetype;
@@ -25,13 +26,56 @@ pub mod archetype;
mod graph;
#[derive(Debug)]
-pub struct ArchetypeSearchTerms<'a>
+pub struct SearchTerms<const TERM_CAP: usize>
{
- pub present: &'a [Uid],
- pub absent: &'a [Uid],
+ pub(crate) present: ArrayVec<Uid, TERM_CAP>,
+ pub(crate) absent: ArrayVec<Uid, TERM_CAP>,
+ pub(crate) traverse: ArrayVec<Traversal<TERM_CAP>, TERM_CAP>,
}
-impl ArchetypeSearchTerms<'_>
+#[derive(Debug, Clone, Copy, PartialEq, Eq)]
+pub struct TermMetadata
+{
+ pub level: u32,
+ pub index: u32,
+}
+
+#[derive(Debug, Clone)]
+pub struct Traversal<const TERM_CAP: usize>
+{
+ pub kind: TraversalKind,
+ pub relation: Uid,
+ pub terms: fn(&Self) -> SearchTerms<TERM_CAP>,
+ pub term_metadata: TermMetadata,
+}
+
+impl<const TERM_CAP: usize> Traversal<TERM_CAP>
+{
+ fn relationship(&self) -> Uid
+ {
+ Uid::new_pair(&PairParams {
+ relation: self.relation,
+ target: Uid::wildcard(),
+ })
+ }
+}
+
+#[derive(Debug, Clone, Copy, PartialEq, Eq)]
+#[non_exhaustive]
+pub enum TraversalKind
+{
+ Up,
+}
+
+#[derive(Debug)]
+pub struct TraversalResult
+{
+ pub relation: Uid,
+ pub term_metadata: TermMetadata,
+ pub found_ent: Uid,
+}
+
+impl<const TERM_CAP: usize> SearchTerms<TERM_CAP>
{
fn excluded_contains(&self, comp_id: Uid) -> bool
{
@@ -55,11 +99,9 @@ impl ArchetypeSearchTerms<'_>
fn contains_conflicting(&self) -> bool
{
- self.absent.iter().any(|excluded_comp_id| {
- self.present
- .binary_search(excluded_comp_id)
- .is_ok()
- })
+ self.absent
+ .iter()
+ .any(|excluded_comp_id| self.present.binary_search(excluded_comp_id).is_ok())
}
fn archetype_contains_all_required(&self, archetype: &Archetype) -> bool
@@ -80,12 +122,12 @@ pub struct Storage
impl Storage
{
- pub fn search_archetypes<'search_terms>(
+ pub fn search_archetypes<'search_terms, const TERM_CAP: usize>(
&self,
- search_terms: ArchetypeSearchTerms<'search_terms>,
- ) -> ArchetypeRefIter<'_, 'search_terms>
+ search_terms: &'search_terms SearchTerms<TERM_CAP>,
+ ) -> ArchetypeRefIter<'_, 'search_terms, TERM_CAP>
{
- let archetype_id = ArchetypeId::new(search_terms.present);
+ let archetype_id = ArchetypeId::new(search_terms.present.iter());
if search_terms.contains_conflicting() {
return ArchetypeRefIter {
@@ -370,9 +412,9 @@ impl Storage
}
}
- fn find_all_archetype_with_comps(
+ fn find_all_archetype_with_comps<const TERM_CAP: usize>(
&self,
- search_terms: &ArchetypeSearchTerms<'_>,
+ search_terms: &SearchTerms<TERM_CAP>,
) -> Vec<ArchetypeId>
{
let Some(mut search_iter) =
@@ -594,29 +636,52 @@ pub enum VizoxideArchetypeGraphEdgeKind
}
#[derive(Debug)]
-pub struct ArchetypeRefIter<'storage, 'search_terms>
+pub struct ArchetypeRefIter<'storage, 'search_terms, const TERM_CAP: usize>
{
storage: &'storage Storage,
pre_iter: Either<ArrayIter<ArchetypeId, 1>, VecIntoIter<ArchetypeId>>,
dfs_iter: ArchetypeAddEdgeDfsIter<'storage>,
- search_terms: ArchetypeSearchTerms<'search_terms>,
+ search_terms: &'search_terms SearchTerms<TERM_CAP>,
}
-impl<'component_storage> Iterator for ArchetypeRefIter<'component_storage, '_>
+impl<'component_storage, const TERM_CAP: usize> Iterator
+ for ArchetypeRefIter<'component_storage, '_, TERM_CAP>
{
- type Item = &'component_storage Archetype;
+ type Item = (
+ &'component_storage Archetype,
+ ArrayVec<TraversalResult, TERM_CAP>,
+ );
fn next(&mut self) -> Option<Self::Item>
{
- if let Some(pre_iter_archetype_id) = self.pre_iter.next() {
- return Some(
- self.storage
- .get_archetype_by_id(pre_iter_archetype_id)
- .expect("Archetype should exist"),
- );
+ if let Some((pre_iter_archetype, pre_iter_traversal_results)) =
+ self.pre_iter.find_map(|archetype_id| {
+ let archetype = self
+ .storage
+ .get_archetype_by_id(archetype_id)
+ .expect("Archetype should exist");
+
+ let mut traversal_results =
+ ArrayVec::<TraversalResult, TERM_CAP>::default();
+
+ if do_traversals(
+ self.storage,
+ archetype,
+ &self.search_terms.traverse,
+ &mut traversal_results,
+ )
+ .is_none()
+ {
+ return None;
+ };
+
+ Some((archetype, traversal_results))
+ })
+ {
+ return Some((pre_iter_archetype, pre_iter_traversal_results));
}
- let archetype_id = loop {
+ let (archetype, traversal_results) = loop {
match self.dfs_iter.streaming_find(|res| {
matches!(
res,
@@ -633,7 +698,27 @@ impl<'component_storage> Iterator for ArchetypeRefIter<'component_storage, '_>
continue;
}
- break add_edge_archetype_id;
+ let add_edge_archetype = self
+ .storage
+ .get_archetype_by_id(add_edge_archetype_id)
+ .expect("Archetype should exist");
+
+ let mut traversal_results =
+ ArrayVec::<TraversalResult, TERM_CAP>::default();
+
+ if do_traversals(
+ self.storage,
+ add_edge_archetype,
+ &self.search_terms.traverse,
+ &mut traversal_results,
+ )
+ .is_none()
+ {
+ self.dfs_iter.pop();
+ continue;
+ };
+
+ break (add_edge_archetype, traversal_results);
}
ArchetypeAddEdgeDfsIterResult::AddEdgeArchetypeNotFound {
archetype,
@@ -644,8 +729,9 @@ impl<'component_storage> Iterator for ArchetypeRefIter<'component_storage, '_>
continue;
}
- let mut add_edge_archetype_comps =
- archetype.component_ids_sorted().collect::<Vec<_>>();
+ let mut add_edge_archetype_comps = archetype
+ .component_ids_sorted()
+ .collect::<ArrayVec<_, 32>>();
add_edge_archetype_comps
.insert_at_part_pt_by_key(add_edge_component_id, |comp_id| {
@@ -659,13 +745,14 @@ impl<'component_storage> Iterator for ArchetypeRefIter<'component_storage, '_>
},
);
- let found =
- self.find_edges_of_imaginary_archetype(&add_edge_archetype_comps);
+ let found = self.find_edges_of_imaginary_archetype(
+ add_edge_archetype_comps.clone(),
+ );
self.dfs_iter.push((
BorrowedOrOwned::Owned(Archetype::new(
add_edge_archetype_id,
- add_edge_archetype_comps.clone(),
+ add_edge_archetype_comps,
)),
found.into_iter(),
));
@@ -676,25 +763,22 @@ impl<'component_storage> Iterator for ArchetypeRefIter<'component_storage, '_>
}
};
- Some(
- self.storage
- .get_archetype_by_id(archetype_id)
- .expect("Archetype should exist"),
- )
+ Some((archetype, traversal_results))
}
}
-impl ArchetypeRefIter<'_, '_>
+impl<const TERM_CAP: usize> ArchetypeRefIter<'_, '_, TERM_CAP>
{
fn find_edges_of_imaginary_archetype(
&self,
- imaginary_archetype_comps: &[Uid],
+ imaginary_archetype_comps: ArrayVec<Uid, 32>,
) -> Vec<(Uid, ArchetypeEdges)>
{
self.storage
- .find_all_archetype_with_comps(&ArchetypeSearchTerms {
- present: imaginary_archetype_comps,
- absent: &[],
+ .find_all_archetype_with_comps(&SearchTerms {
+ present: imaginary_archetype_comps.clone(),
+ absent: ArrayVec::default(),
+ traverse: ArrayVec::default(),
})
.into_iter()
.filter_map(|found_id| {
@@ -757,7 +841,75 @@ pub struct EntityAlreadyExistsError;
struct ImaginaryArchetype
{
id: ArchetypeId,
- component_ids: Vec<Uid>,
+ component_ids: ArrayVec<Uid, 32>,
+}
+
+fn do_traversals<const TERM_CAP: usize>(
+ storage: &Storage,
+ archetype: &Archetype,
+ traversals: &[Traversal<TERM_CAP>],
+ results: &mut ArrayVec<TraversalResult, TERM_CAP>,
+) -> Option<()>
+{
+ // TODO: Optimize traversals. Caching is needed especially
+
+ for traversal in traversals {
+ if traversal.kind == TraversalKind::Up {
+ archetype
+ .get_matching_component_ids(traversal.relationship())
+ .find_map(|relationship| {
+ traverse_dfs(
+ storage,
+ relationship.target(),
+ traversal,
+ &(traversal.terms)(traversal),
+ results,
+ )
+ })?;
+ } else {
+ unimplemented!();
+ }
+ }
+
+ Some(())
+}
+
+fn traverse_dfs<const TERM_CAP: usize>(
+ storage: &Storage,
+ ent_id: Uid,
+ traversal: &Traversal<TERM_CAP>,
+ terms: &SearchTerms<TERM_CAP>,
+ results: &mut ArrayVec<TraversalResult, TERM_CAP>,
+) -> Option<()>
+{
+ let ent_archetype = storage.get_entity_archetype(ent_id)?;
+
+ if terms
+ .absent
+ .iter()
+ .all(|absent_comp_id| !ent_archetype.contains_matching_component(*absent_comp_id))
+ && terms.archetype_contains_all_required(ent_archetype)
+ && do_traversals(storage, ent_archetype, &terms.traverse, results).is_some()
+ {
+ results.push(TraversalResult {
+ relation: traversal.relation,
+ term_metadata: traversal.term_metadata,
+ found_ent: ent_id,
+ });
+
+ return Some(());
+ }
+
+ for relationship in ent_archetype.get_matching_component_ids(traversal.relationship())
+ {
+ if traverse_dfs(storage, relationship.target(), traversal, terms, results)
+ .is_some()
+ {
+ return Some(());
+ }
+ }
+
+ None
}
#[cfg(test)]