diff options
Diffstat (limited to 'ecs/src')
-rw-r--r-- | ecs/src/component.rs | 22 | ||||
-rw-r--r-- | ecs/src/component/storage.rs | 45 | ||||
-rw-r--r-- | ecs/src/component/storage/graph.rs | 17 | ||||
-rw-r--r-- | ecs/src/lib.rs | 12 | ||||
-rw-r--r-- | ecs/src/query.rs | 126 | ||||
-rw-r--r-- | ecs/src/query/flexible.rs | 8 | ||||
-rw-r--r-- | ecs/src/query/term.rs | 8 | ||||
-rw-r--r-- | ecs/src/util.rs | 2 | ||||
-rw-r--r-- | ecs/src/util/array_vec.rs | 115 |
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, + } + } +} |