summaryrefslogtreecommitdiff
path: root/ecs/src
diff options
context:
space:
mode:
Diffstat (limited to 'ecs/src')
-rw-r--r--ecs/src/component.rs22
-rw-r--r--ecs/src/component/storage.rs45
-rw-r--r--ecs/src/component/storage/graph.rs17
-rw-r--r--ecs/src/lib.rs12
-rw-r--r--ecs/src/query.rs126
-rw-r--r--ecs/src/query/flexible.rs8
-rw-r--r--ecs/src/query/term.rs8
-rw-r--r--ecs/src/util.rs2
-rw-r--r--ecs/src/util/array_vec.rs115
9 files changed, 242 insertions, 113 deletions
diff --git a/ecs/src/component.rs b/ecs/src/component.rs
index 46fbf8a..525bd98 100644
--- a/ecs/src/component.rs
+++ b/ecs/src/component.rs
@@ -50,12 +50,6 @@ pub trait Component: SystemInput + Any + TypeName
/// Returns the component UID of a component event for this component.
fn get_event_uid(&self, event_kind: ComponentEventKind) -> Uid;
- #[doc(hidden)]
- fn as_any_mut(&mut self) -> &mut dyn Any;
-
- #[doc(hidden)]
- fn as_any(&self) -> &dyn Any;
-
/// Returns whether the component `self` is optional.
fn self_is_optional(&self) -> bool
{
@@ -76,17 +70,17 @@ impl dyn Component
{
pub fn downcast_mut<Real: 'static>(&mut self) -> Option<&mut Real>
{
- self.as_any_mut().downcast_mut()
+ (self as &mut dyn Any).downcast_mut()
}
pub fn downcast_ref<Real: 'static>(&self) -> Option<&Real>
{
- self.as_any().downcast_ref()
+ (self as &dyn Any).downcast_ref()
}
pub fn is<Other: 'static>(&self) -> bool
{
- self.as_any().is::<Other>()
+ (self as &dyn Any).is::<Other>()
}
}
@@ -128,16 +122,6 @@ where
}
}
- fn as_any_mut(&mut self) -> &mut dyn Any
- {
- self
- }
-
- fn as_any(&self) -> &dyn Any
- {
- self
- }
-
fn self_is_optional(&self) -> bool
{
true
diff --git a/ecs/src/component/storage.rs b/ecs/src/component/storage.rs
index 4a00510..0a6382b 100644
--- a/ecs/src/component/storage.rs
+++ b/ecs/src/component/storage.rs
@@ -192,41 +192,39 @@ impl Storage
});
}
- let add_edge_archetype_id = archetype_node
+ let add_edge_archetype_id = match archetype_node
.get_or_insert_edges(component_id, ArchetypeEdges::default)
.add
- .unwrap_or_else(|| {
+ {
+ 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
.graph
- .get_node_by_id_mut(archetype_id)
+ .get_node_by_id(archetype_id)
.expect("Archetype should exist");
let (add_edge_id, add_edge_comp_ids) =
archetype_node.make_add_edge(component_id);
- archetype_node
- .get_edges_mut(component_id)
- .expect("Edges for component in archetype should exist")
- .add = Some(add_edge_id);
-
if !self.graph.contains_archetype(add_edge_id) {
self.graph.create_node(add_edge_id, &add_edge_comp_ids);
}
add_edge_id
- });
-
- {
- let add_edge_archetype_node = self
- .graph
- .get_node_by_id_mut(add_edge_archetype_id)
- .expect("Add edge archetype should exist");
-
- let add_edge_archetype_edges = add_edge_archetype_node
- .get_or_insert_edges(component_id, ArchetypeEdges::default);
-
- add_edge_archetype_edges.remove = Some(archetype_id);
- }
+ }
+ };
let archetype_node = self
.graph
@@ -297,11 +295,6 @@ impl Storage
let (remove_edge_id, remove_edge_comp_ids) =
archetype_node.make_remove_edge(component_id);
- archetype_node
- .get_edges_mut(component_id)
- .expect("Edges for component in archetype should exist")
- .remove = Some(remove_edge_id);
-
if !self.graph.contains_archetype(remove_edge_id) {
self.graph
.create_node(remove_edge_id, &remove_edge_comp_ids);
diff --git a/ecs/src/component/storage/graph.rs b/ecs/src/component/storage/graph.rs
index 11160e7..d38223a 100644
--- a/ecs/src/component/storage/graph.rs
+++ b/ecs/src/component/storage/graph.rs
@@ -140,7 +140,7 @@ impl Graph
}
fn create_missing_subset_node_edges(
- target_node: &ArchetypeNode,
+ target_node: &mut ArchetypeNode,
subset_node: &mut ArchetypeNode,
)
{
@@ -153,6 +153,14 @@ impl Graph
subset_node
.get_or_insert_edges(uniq_comp_id, ArchetypeEdges::default)
.add = Some(subset_node.make_add_edge(uniq_comp_id).0);
+
+ if target_node.archetype().component_cnt()
+ == subset_node.archetype().component_cnt() + 1
+ {
+ target_node
+ .get_or_insert_edges(uniq_comp_id, ArchetypeEdges::default)
+ .remove = Some(subset_node.archetype().id());
+ }
}
fn create_missing_superset_node_edges(
@@ -245,13 +253,6 @@ impl ArchetypeNode
self.edges.iter()
}
- pub fn get_edges_mut(&mut self, component_id: Uid) -> Option<&mut ArchetypeEdges>
- {
- debug_assert_eq!(component_id.kind(), UidKind::Component);
-
- self.edges.get_mut(&component_id)
- }
-
pub fn make_add_edge(&self, component_id: Uid) -> (ArchetypeId, Vec<Uid>)
{
let mut edge_comp_ids = self
diff --git a/ecs/src/lib.rs b/ecs/src/lib.rs
index 3caaa6b..32d82bc 100644
--- a/ecs/src/lib.rs
+++ b/ecs/src/lib.rs
@@ -184,10 +184,10 @@ impl World
Query::new(self)
}
- pub fn flexible_query<'terms>(
+ pub fn flexible_query<const MAX_TERM_CNT: usize>(
&self,
- terms: QueryTerms<'terms>,
- ) -> FlexibleQuery<'_, 'terms>
+ terms: QueryTerms<MAX_TERM_CNT>,
+ ) -> FlexibleQuery<'_, MAX_TERM_CNT>
{
FlexibleQuery::new(self, terms)
}
@@ -536,11 +536,9 @@ impl World
fn emit_event_by_id(&self, event_id: Uid)
{
- let mut query_required_ids = [SystemComponent::id(), event_id];
-
let query = self.flexible_query(
- QueryTerms::builder()
- .with_required_ids(&mut query_required_ids)
+ QueryTerms::<2>::builder()
+ .with_required([SystemComponent::id(), event_id])
.build(),
);
diff --git a/ecs/src/query.rs b/ecs/src/query.rs
index d7d2d1c..b29db3d 100644
--- a/ecs/src/query.rs
+++ b/ecs/src/query.rs
@@ -1,5 +1,4 @@
use std::any::type_name;
-use std::borrow::Cow;
use std::marker::PhantomData;
use seq_macro::seq;
@@ -9,7 +8,8 @@ use crate::entity::Handle as EntityHandle;
use crate::query::flexible::{Iter as FlexibleQueryIter, Query as FlexibleQuery};
use crate::system::{Param as SystemParam, System};
use crate::uid::Uid;
-use crate::util::VecExt;
+use crate::util::array_vec::ArrayVec;
+use crate::util::Array;
use crate::World;
pub mod flexible;
@@ -22,7 +22,8 @@ where
FieldlessTerms: TermWithoutFieldTuple,
{
world: &'world World,
- inner: FlexibleQuery<'world, 'static>,
+ // A term tuple type can have a maximum of 17 elements
+ inner: FlexibleQuery<'world, 17>,
_pd: PhantomData<(FieldTerms, FieldlessTerms)>,
}
@@ -147,43 +148,47 @@ where
}
#[derive(Debug)]
-pub struct Terms<'a>
+pub struct Terms<const MAX_TERM_CNT: usize>
{
- required_components: Cow<'a, [Uid]>,
- excluded_components: Cow<'a, [Uid]>,
+ required_components: ArrayVec<Uid, MAX_TERM_CNT>,
+ excluded_components: ArrayVec<Uid, MAX_TERM_CNT>,
}
-impl<'a> Terms<'a>
+impl<const MAX_TERM_CNT: usize> Terms<MAX_TERM_CNT>
{
- pub fn builder() -> TermsBuilder<'a>
+ pub fn builder() -> TermsBuilder<MAX_TERM_CNT>
{
TermsBuilder::default()
}
}
#[derive(Debug, Default)]
-pub struct TermsBuilder<'a>
+pub struct TermsBuilder<const MAX_TERM_CNT: usize>
{
- required_components: Cow<'a, [Uid]>,
- excluded_components: Cow<'a, [Uid]>,
+ required_components: ArrayVec<Uid, MAX_TERM_CNT>,
+ excluded_components: ArrayVec<Uid, MAX_TERM_CNT>,
}
-pub trait TermsBuilderInterface<'a>
+pub trait TermsBuilderInterface
{
fn with<ComponentT: Component>(self) -> Self;
fn without<ComponentT: Component>(self) -> Self;
- fn with_required_ids(self, ids: &'a mut [Uid]) -> Self;
+ fn with_required(self, ids: impl Array<Uid>) -> Self;
}
macro_rules! impl_terms_builder {
($($impl_content: tt)*) => {
- impl<'a> TermsBuilderInterface<'a> for TermsBuilder<'a> {
+ impl<const MAX_TERM_CNT: usize>
+ TermsBuilderInterface for TermsBuilder<MAX_TERM_CNT>
+ {
$($impl_content)*
}
- impl<'a> TermsBuilderInterface<'a> for &mut TermsBuilder<'a> {
+ impl<const MAX_TERM_CNT: usize>
+ TermsBuilderInterface for &mut TermsBuilder<MAX_TERM_CNT>
+ {
$($impl_content)*
}
};
@@ -197,9 +202,11 @@ impl_terms_builder! {
return self;
}
+ let insert_index = self.required_components
+ .partition_point(|id| *id <= ComponentT::id());
+
self.required_components
- .to_mut()
- .insert_at_partition_point_by_key(ComponentT::id(), |id| *id);
+ .insert(insert_index, ComponentT::id());
self
}
@@ -214,48 +221,51 @@ impl_terms_builder! {
);
}
+ let insert_index = self.excluded_components
+ .partition_point(|id| *id <= ComponentT::id());
+
self.excluded_components
- .to_mut()
- .insert_at_partition_point_by_key(ComponentT::id(), |id| *id);
+ .insert(insert_index, ComponentT::id());
self
}
#[allow(unused_mut)]
- fn with_required_ids(mut self, ids: &'a mut [Uid]) -> Self
+ fn with_required(mut self, mut ids: impl Array<Uid>) -> Self
{
- if ids.is_empty() {
- return self;
+ if !ids.as_ref().is_sorted() {
+ ids.as_mut().sort();
}
- if !ids.is_sorted() {
- ids.sort();
+ if self.required_components.len() == 0 {
+ self.required_components.extend(ids);
+ return self;
}
- if self.required_components.is_empty() {
- self.required_components = Cow::Borrowed(ids);
+ let mut id_iter = ids.into_iter();
- return self;
- }
+ while let Some(id) = id_iter.next() {
+ let insert_index = self.required_components
+ .partition_point(|other_id| *other_id <= id);
- let first_id_pp_index = self.required_components.partition_point(|req_comp_id| {
- req_comp_id <= ids.first().expect("Cannot happend since not empty")
- });
+ if insert_index == self.required_components.len() {
+ self.required_components.extend([id].into_iter().chain(id_iter));
- let removed = self
- .required_components
- .to_mut()
- .splice(first_id_pp_index..first_id_pp_index, ids.iter().copied());
+ return self;
+ }
- assert_eq!(removed.count(), 0);
+ self.required_components
+ .insert(insert_index, id);
+
+ }
self
}
}
-impl<'a> TermsBuilder<'a>
+impl<const MAX_TERM_CNT: usize> TermsBuilder<MAX_TERM_CNT>
{
- pub fn build(self) -> Terms<'a>
+ pub fn build(self) -> Terms<MAX_TERM_CNT>
{
assert!(self.required_components.is_sorted());
assert!(self.excluded_components.is_sorted());
@@ -269,14 +279,18 @@ impl<'a> TermsBuilder<'a>
pub trait TermWithoutField
{
- fn apply_to_terms_builder(terms_builder: &mut TermsBuilder<'_>);
+ fn apply_to_terms_builder<const MAX_TERM_CNT: usize>(
+ terms_builder: &mut TermsBuilder<MAX_TERM_CNT>,
+ );
}
pub trait TermWithField
{
type Field<'a>;
- fn apply_to_terms_builder(terms_builder: &mut TermsBuilder<'_>);
+ fn apply_to_terms_builder<const MAX_TERM_CNT: usize>(
+ terms_builder: &mut TermsBuilder<MAX_TERM_CNT>,
+ );
fn get_field<'world>(
entity_handle: &EntityHandle<'world>,
@@ -288,7 +302,9 @@ impl<ComponentRefT: ComponentRef> TermWithField for ComponentRefT
{
type Field<'a> = ComponentRefT::Handle<'a>;
- fn apply_to_terms_builder(terms_builder: &mut TermsBuilder<'_>)
+ fn apply_to_terms_builder<const MAX_TERM_CNT: usize>(
+ terms_builder: &mut TermsBuilder<MAX_TERM_CNT>,
+ )
{
terms_builder.with::<ComponentRefT::Component>();
}
@@ -315,14 +331,18 @@ impl<ComponentRefT: ComponentRef> TermWithField for ComponentRefT
pub trait TermWithoutFieldTuple
{
- fn apply_terms_to_builder(terms_builder: &mut TermsBuilder<'_>);
+ fn apply_terms_to_builder<const MAX_TERM_CNT: usize>(
+ terms_builder: &mut TermsBuilder<MAX_TERM_CNT>,
+ );
}
pub trait TermWithFieldTuple
{
type Fields<'component>;
- fn apply_terms_to_builder(terms_builder: &mut TermsBuilder<'_>);
+ fn apply_terms_to_builder<const MAX_TERM_CNT: usize>(
+ terms_builder: &mut TermsBuilder<MAX_TERM_CNT>,
+ );
fn get_fields<'component>(
entity_handle: &EntityHandle<'component>,
@@ -411,7 +431,9 @@ macro_rules! impl_term_sequence {
seq!(I in 0..=$c {
impl<#(Term~I: TermWithoutField,)*> TermWithoutFieldTuple for (#(Term~I,)*)
{
- fn apply_terms_to_builder(terms_builder: &mut TermsBuilder<'_>)
+ fn apply_terms_to_builder<const MAX_TERM_CNT: usize>(
+ terms_builder: &mut TermsBuilder<MAX_TERM_CNT>
+ )
{
#(
Term~I::apply_to_terms_builder(terms_builder);
@@ -423,7 +445,9 @@ macro_rules! impl_term_sequence {
{
type Fields<'component> = (#(Term~I::Field<'component>,)*);
- fn apply_terms_to_builder(terms_builder: &mut TermsBuilder<'_>)
+ fn apply_terms_to_builder<const MAX_TERM_CNT: usize>(
+ terms_builder: &mut TermsBuilder<MAX_TERM_CNT>
+ )
{
#(
Term~I::apply_to_terms_builder(terms_builder);
@@ -448,14 +472,22 @@ seq!(C in 0..=16 {
impl TermWithoutFieldTuple for ()
{
- fn apply_terms_to_builder(_terms_builder: &mut TermsBuilder<'_>) {}
+ fn apply_terms_to_builder<const MAX_TERM_CNT: usize>(
+ _terms_builder: &mut TermsBuilder<MAX_TERM_CNT>,
+ )
+ {
+ }
}
impl TermWithFieldTuple for ()
{
type Fields<'component> = ();
- fn apply_terms_to_builder(_terms_builder: &mut TermsBuilder<'_>) {}
+ fn apply_terms_to_builder<const MAX_TERM_CNT: usize>(
+ _terms_builder: &mut TermsBuilder<MAX_TERM_CNT>,
+ )
+ {
+ }
fn get_fields<'component>(
_entity_handle: &EntityHandle<'_>,
diff --git a/ecs/src/query/flexible.rs b/ecs/src/query/flexible.rs
index 652b96f..2f0b5e7 100644
--- a/ecs/src/query/flexible.rs
+++ b/ecs/src/query/flexible.rs
@@ -14,13 +14,13 @@ use crate::World;
/// Low-level entity query structure.
#[derive(Debug)]
-pub struct Query<'world, 'terms>
+pub struct Query<'world, const MAX_TERM_CNT: usize>
{
component_storage: ReadGuard<'world, ComponentStorage>,
- terms: Terms<'terms>,
+ terms: Terms<MAX_TERM_CNT>,
}
-impl<'world, 'terms> Query<'world, 'terms>
+impl<'world, const MAX_TERM_CNT: usize> Query<'world, MAX_TERM_CNT>
{
/// Iterates over the entities matching this query.
#[must_use]
@@ -42,7 +42,7 @@ impl<'world, 'terms> Query<'world, 'terms>
}
}
- pub(crate) fn new(world: &'world World, terms: Terms<'terms>) -> Self
+ pub(crate) fn new(world: &'world World, terms: Terms<MAX_TERM_CNT>) -> Self
{
Self {
component_storage: world
diff --git a/ecs/src/query/term.rs b/ecs/src/query/term.rs
index 7f24147..ce453f0 100644
--- a/ecs/src/query/term.rs
+++ b/ecs/src/query/term.rs
@@ -14,7 +14,9 @@ impl<ComponentT> TermWithoutField for With<ComponentT>
where
ComponentT: Component,
{
- fn apply_to_terms_builder(terms_builder: &mut TermsBuilder<'_>)
+ fn apply_to_terms_builder<const MAX_TERM_CNT: usize>(
+ terms_builder: &mut TermsBuilder<MAX_TERM_CNT>,
+ )
{
terms_builder.with::<ComponentT>();
}
@@ -31,7 +33,9 @@ impl<ComponentT> TermWithoutField for Without<ComponentT>
where
ComponentT: Component,
{
- fn apply_to_terms_builder(terms_builder: &mut TermsBuilder<'_>)
+ fn apply_to_terms_builder<const MAX_TERM_CNT: usize>(
+ terms_builder: &mut TermsBuilder<MAX_TERM_CNT>,
+ )
{
terms_builder.without::<ComponentT>();
}
diff --git a/ecs/src/util.rs b/ecs/src/util.rs
index 6f7aed7..eb06ab4 100644
--- a/ecs/src/util.rs
+++ b/ecs/src/util.rs
@@ -4,6 +4,8 @@ use std::ops::{BitAnd, Deref};
use hashbrown::HashMap;
+pub mod array_vec;
+
pub trait VecExt<Item>
{
fn insert_at_partition_point_by_key<Key>(
diff --git a/ecs/src/util/array_vec.rs b/ecs/src/util/array_vec.rs
new file mode 100644
index 0000000..648c976
--- /dev/null
+++ b/ecs/src/util/array_vec.rs
@@ -0,0 +1,115 @@
+use std::mem::{transmute, MaybeUninit};
+use std::ops::{Deref, DerefMut};
+
+#[derive(Debug)]
+pub struct ArrayVec<Item, const CAPACITY: usize>
+{
+ items: [MaybeUninit<Item>; CAPACITY],
+ len: usize,
+}
+
+impl<Item, const CAPACITY: usize> ArrayVec<Item, CAPACITY>
+{
+ pub fn new() -> Self
+ {
+ Self::default()
+ }
+
+ #[inline]
+ #[must_use]
+ pub fn len(&self) -> usize
+ {
+ self.len
+ }
+
+ pub fn push(&mut self, item: Item)
+ {
+ assert!(self.len < CAPACITY);
+
+ self.items[self.len].write(item);
+
+ self.len += 1;
+ }
+
+ pub fn insert(&mut self, index: usize, item: Item)
+ {
+ assert!(index <= self.len);
+ assert!(self.len < CAPACITY);
+
+ if index == self.len {
+ self.push(item);
+ return;
+ }
+
+ unsafe {
+ std::ptr::copy(
+ &self.items[index],
+ &mut self.items[index + 1],
+ self.len - index,
+ );
+ }
+
+ self.items[index].write(item);
+
+ self.len += 1;
+ }
+}
+
+impl<Item, const CAPACITY: usize> Extend<Item> for ArrayVec<Item, CAPACITY>
+{
+ fn extend<IntoIter: IntoIterator<Item = Item>>(&mut self, iter: IntoIter)
+ {
+ for item in iter {
+ self.push(item);
+ }
+ }
+}
+
+impl<Item, const CAPACITY: usize> AsRef<[Item]> for ArrayVec<Item, CAPACITY>
+{
+ fn as_ref(&self) -> &[Item]
+ {
+ unsafe { transmute::<&[MaybeUninit<Item>], &[Item]>(&self.items[..self.len]) }
+ }
+}
+
+impl<Item, const CAPACITY: usize> AsMut<[Item]> for ArrayVec<Item, CAPACITY>
+{
+ fn as_mut(&mut self) -> &mut [Item]
+ {
+ unsafe {
+ transmute::<&mut [MaybeUninit<Item>], &mut [Item]>(
+ &mut self.items[..self.len],
+ )
+ }
+ }
+}
+
+impl<Item, const CAPACITY: usize> Deref for ArrayVec<Item, CAPACITY>
+{
+ type Target = [Item];
+
+ fn deref(&self) -> &Self::Target
+ {
+ self.as_ref()
+ }
+}
+
+impl<Item, const CAPACITY: usize> DerefMut for ArrayVec<Item, CAPACITY>
+{
+ fn deref_mut(&mut self) -> &mut Self::Target
+ {
+ self.as_mut()
+ }
+}
+
+impl<Item, const CAPACITY: usize> Default for ArrayVec<Item, CAPACITY>
+{
+ fn default() -> Self
+ {
+ Self {
+ items: [const { MaybeUninit::uninit() }; CAPACITY],
+ len: 0,
+ }
+ }
+}