diff options
Diffstat (limited to 'ecs/src')
-rw-r--r-- | ecs/src/actions.rs | 54 | ||||
-rw-r--r-- | ecs/src/component.rs | 496 | ||||
-rw-r--r-- | ecs/src/component/storage.rs | 181 | ||||
-rw-r--r-- | ecs/src/component/storage/archetype.rs | 177 | ||||
-rw-r--r-- | ecs/src/component/storage/graph.rs | 36 | ||||
-rw-r--r-- | ecs/src/entity.rs | 109 | ||||
-rw-r--r-- | ecs/src/event/component.rs | 88 | ||||
-rw-r--r-- | ecs/src/lib.rs | 494 | ||||
-rw-r--r-- | ecs/src/lock.rs | 95 | ||||
-rw-r--r-- | ecs/src/pair.rs | 198 | ||||
-rw-r--r-- | ecs/src/phase.rs | 6 | ||||
-rw-r--r-- | ecs/src/query.rs | 273 | ||||
-rw-r--r-- | ecs/src/query/flexible.rs | 39 | ||||
-rw-r--r-- | ecs/src/query/term.rs | 109 | ||||
-rw-r--r-- | ecs/src/relationship.rs | 466 | ||||
-rw-r--r-- | ecs/src/sole.rs | 11 | ||||
-rw-r--r-- | ecs/src/system/stateful.rs | 9 | ||||
-rw-r--r-- | ecs/src/type_name.rs | 15 | ||||
-rw-r--r-- | ecs/src/uid.rs | 177 | ||||
-rw-r--r-- | ecs/src/util.rs | 2 | ||||
-rw-r--r-- | ecs/src/util/array_vec.rs | 131 |
21 files changed, 1677 insertions, 1489 deletions
diff --git a/ecs/src/actions.rs b/ecs/src/actions.rs index 7dff3a5..3dd8755 100644 --- a/ecs/src/actions.rs +++ b/ecs/src/actions.rs @@ -1,11 +1,7 @@ use std::marker::PhantomData; -use std::sync::{Arc, Weak}; +use std::rc::{Rc, Weak}; -use crate::component::{ - Component, - Metadata as ComponentMetadata, - Sequence as ComponentSequence, -}; +use crate::component::{Parts as ComponentParts, Sequence as ComponentSequence}; use crate::system::{Param as SystemParam, System}; use crate::uid::{Kind as UidKind, Uid}; use crate::{ActionQueue, World}; @@ -23,13 +19,11 @@ impl<'world> Actions<'world> /// Queues up a entity to spawn at the end of the current tick. pub fn spawn<Comps: ComponentSequence>(&mut self, components: Comps) { - self.action_queue.push(Action::Spawn( - components.into_array().into(), - EventIds { ids: Comps::added_event_ids() }, - )); + self.action_queue + .push(Action::Spawn(components.into_parts_array().into())); } - /// Queues up despawning a entity at the end of the current tick. + /// Queues up despawning a entity at the end of the **next** tick. pub fn despawn(&mut self, entity_uid: Uid) { debug_assert_eq!(entity_uid.kind(), UidKind::Entity); @@ -50,26 +44,28 @@ impl<'world> Actions<'world> self.action_queue.push(Action::AddComponents( entity_uid, - components.into_array().into(), - EventIds { ids: Comps::added_event_ids() }, + components.into_parts_array().into(), )); } - /// Queues up removing component(s) from a entity at the end of the current tick. - pub fn remove_components<Comps>(&mut self, entity_uid: Uid) - where - Comps: ComponentSequence, + /// Queues up removing component(s) from a entity at the end of the **next** tick. + pub fn remove_components( + &mut self, + entity_uid: Uid, + component_ids: impl IntoIterator<Item = Uid>, + ) { debug_assert_eq!(entity_uid.kind(), UidKind::Entity); - if Comps::COUNT == 0 { + let mut component_ids = component_ids.into_iter().peekable(); + + if component_ids.peek().is_none() { return; } self.action_queue.push(Action::RemoveComponents( entity_uid, - Comps::metadata().into_iter().collect(), - EventIds { ids: Comps::removed_event_ids() }, + component_ids.collect(), )); } @@ -91,11 +87,11 @@ impl<'world> Actions<'world> } } - fn new(action_queue: &'world Arc<ActionQueue>) -> Self + fn new(action_queue: &'world Rc<ActionQueue>) -> Self { Self { action_queue, - action_queue_weak: Arc::downgrade(action_queue), + action_queue_weak: Rc::downgrade(action_queue), } } } @@ -146,7 +142,7 @@ impl WeakRef #[derive(Debug, Clone)] pub struct Ref<'weak_ref> { - action_queue: Arc<ActionQueue>, + action_queue: Rc<ActionQueue>, _pd: PhantomData<&'weak_ref ()>, } @@ -159,19 +155,13 @@ impl Ref<'_> } } -#[derive(Debug)] -pub(crate) struct EventIds -{ - pub(crate) ids: Vec<Uid>, -} - /// A action for a [`System`] to perform. #[derive(Debug)] pub(crate) enum Action { - Spawn(Vec<(Uid, Box<dyn Component>)>, EventIds), + Spawn(Vec<ComponentParts>), Despawn(Uid), - AddComponents(Uid, Vec<(Uid, Box<dyn Component>)>, EventIds), - RemoveComponents(Uid, Vec<ComponentMetadata>, EventIds), + AddComponents(Uid, Vec<ComponentParts>), + RemoveComponents(Uid, Vec<Uid>), Stop, } diff --git a/ecs/src/component.rs b/ecs/src/component.rs index 525bd98..5a8cd0b 100644 --- a/ecs/src/component.rs +++ b/ecs/src/component.rs @@ -2,68 +2,35 @@ use std::any::{type_name, Any}; use std::fmt::Debug; use std::ops::{Deref, DerefMut}; +use ecs_macros::Component; +use hashbrown::HashSet; use seq_macro::seq; -use crate::event::component::{ - Added as ComponentAddedEvent, - Kind as ComponentEventKind, - Removed as ComponentRemovedEvent, -}; use crate::lock::{ Error as LockError, - Lock, MappedReadGuard, MappedWriteGuard, ReadGuard, WriteGuard, }; use crate::system::Input as SystemInput; -use crate::type_name::TypeName; use crate::uid::Uid; use crate::util::Array; -use crate::World; +use crate::EntityComponentRef; pub mod local; pub(crate) mod storage; -pub trait Component: SystemInput + Any + TypeName +pub trait Component: SystemInput + Any { - /// The component type in question. Will usually be `Self` - type Component: Component - where - Self: Sized; - - type HandleMut<'component>: FromLockedOptional<'component> - where - Self: Sized; - - type Handle<'component>: FromLockedOptional<'component> - where - Self: Sized; - /// Returns the ID of this component. fn id() -> Uid where Self: Sized; - /// Returns the component UID of a component event for this component. - fn get_event_uid(&self, event_kind: ComponentEventKind) -> Uid; - - /// Returns whether the component `self` is optional. - fn self_is_optional(&self) -> bool - { - false - } - - /// Returns whether this component is optional. - #[must_use] - fn is_optional() -> bool - where - Self: Sized, - { - false - } + /// Returns the name of this component. + fn name(&self) -> &'static str; } impl dyn Component @@ -92,199 +59,61 @@ impl Debug for dyn Component } } -impl TypeName for Box<dyn Component> -{ - fn type_name(&self) -> &'static str - { - self.as_ref().type_name() - } -} - -impl<ComponentT> Component for Option<ComponentT> -where - ComponentT: Component, - for<'a> Option<ComponentT::Handle<'a>>: FromLockedOptional<'a>, - for<'a> Option<ComponentT::HandleMut<'a>>: FromLockedOptional<'a>, -{ - type Component = ComponentT; - type Handle<'component> = Option<ComponentT::Handle<'component>>; - type HandleMut<'component> = Option<ComponentT::HandleMut<'component>>; - - fn id() -> Uid - { - ComponentT::id() - } - - fn get_event_uid(&self, event_kind: ComponentEventKind) -> Uid - { - match event_kind { - ComponentEventKind::Removed => ComponentRemovedEvent::<Self>::id(), - } - } - - fn self_is_optional(&self) -> bool - { - true - } - - fn is_optional() -> bool - { - true - } -} - -impl<ComponentT> TypeName for Option<ComponentT> -where - ComponentT: Component, -{ - fn type_name(&self) -> &'static str - { - type_name::<Self>() - } -} - -impl<ComponentT> SystemInput for Option<ComponentT> where ComponentT: Component {} - /// A sequence of components. pub trait Sequence { /// The number of components in this component sequence. const COUNT: usize; - type Array: Array<(Uid, Box<dyn Component>)>; - - fn into_array(self) -> Self::Array; - - fn metadata() -> impl Array<Metadata>; - - fn added_event_ids() -> Vec<Uid>; - - fn removed_event_ids() -> Vec<Uid>; -} - -/// A mutable or immutable reference to a component. -pub trait Ref -{ - type Component: Component; - type Handle<'component>: FromLockedOptional<'component>; -} - -impl<ComponentT> Ref for &ComponentT -where - ComponentT: Component, -{ - type Component = ComponentT; - type Handle<'component> = ComponentT::Handle<'component>; -} - -impl<ComponentT> Ref for &mut ComponentT -where - ComponentT: Component, -{ - type Component = ComponentT; - type Handle<'component> = ComponentT::HandleMut<'component>; -} + type PartsArray: Array<Parts>; -/// [`Component`] metadata. -#[derive(Debug, Clone)] -#[non_exhaustive] -pub struct Metadata -{ - pub id: Uid, - pub is_optional: bool, + fn into_parts_array(self) -> Self::PartsArray; } -impl Metadata +#[derive(Debug)] +pub struct Handle<'a, ComponentData: 'static> { - #[must_use] - pub fn new_non_optional(id: Uid) -> Self - { - Self { id, is_optional: false } - } - - #[must_use] - pub fn of<ComponentT: Component>() -> Self - { - Self { - id: ComponentT::id(), - is_optional: ComponentT::is_optional(), - } - } + inner: MappedReadGuard<'a, ComponentData>, } -pub trait FromLockedOptional<'comp>: Sized +impl<'comp, ComponentData: 'static> Handle<'comp, ComponentData> { - /// Converts a reference to a optional locked boxed component to a instance of `Self`. + /// Creates a new handle instance from a [`EntityComponentRef`]. /// /// # Errors - /// Returns `Err` if taking the lock (in a non-blocking way) fails. - fn from_locked_optional_component( - optional_component: Option<&'comp Lock<Box<dyn Component>>>, - world: &'comp World, - ) -> Result<Self, LockError>; -} - -#[derive(Debug)] -pub struct Handle<'a, ComponentT: Component> -{ - inner: MappedReadGuard<'a, ComponentT>, -} + /// Will return `Err` if acquiring the component's lock fails. + pub fn from_entity_component_ref( + entity_component_ref: EntityComponentRef<'comp>, + ) -> Result<Self, HandleError> + { + Ok(Self::new( + entity_component_ref + .component() + .read_nonblock() + .map_err(AcquireLockError)?, + )) + } -impl<'a, ComponentT: Component> Handle<'a, ComponentT> -{ - pub(crate) fn new(inner: ReadGuard<'a, Box<dyn Component>>) -> Self + pub(crate) fn new(inner: ReadGuard<'comp, Box<dyn Any>>) -> Self { Self { inner: inner.map(|component| { - component.downcast_ref::<ComponentT>().unwrap_or_else(|| { - panic!( - "Cannot downcast component {} to type {}", - component.type_name(), - type_name::<ComponentT>() - ); - }) + component + .downcast_ref::<ComponentData>() + .unwrap_or_else(|| { + panic!( + "Failed to downcast component to type {}", + type_name::<ComponentData>() + ); + }) }), } } } -impl<'component, ComponentT: Component> FromLockedOptional<'component> - for Handle<'component, ComponentT> -{ - fn from_locked_optional_component( - optional_component: Option<&'component crate::lock::Lock<Box<dyn Component>>>, - _world: &'component World, - ) -> Result<Self, LockError> - { - let component = optional_component.unwrap_or_else(|| { - panic!( - "Component {} was not found in entity", - type_name::<ComponentT>() - ); - }); - - Ok(Self::new(component.read_nonblock()?)) - } -} - -impl<'comp, ComponentT> FromLockedOptional<'comp> for Option<Handle<'comp, ComponentT>> -where - ComponentT: Component, -{ - fn from_locked_optional_component( - optional_component: Option<&'comp Lock<Box<dyn Component>>>, - _world: &'comp World, - ) -> Result<Self, LockError> - { - optional_component - .map(|lock| Ok(Handle::new(lock.read_nonblock()?))) - .transpose() - } -} - -impl<ComponentT: Component> Deref for Handle<'_, ComponentT> +impl<ComponentData: 'static> Deref for Handle<'_, ComponentData> { - type Target = ComponentT; + type Target = ComponentData; fn deref(&self) -> &Self::Target { @@ -293,67 +122,49 @@ impl<ComponentT: Component> Deref for Handle<'_, ComponentT> } #[derive(Debug)] -pub struct HandleMut<'a, ComponentT: Component> +pub struct HandleMut<'a, ComponentData: 'static> { - inner: MappedWriteGuard<'a, ComponentT>, + inner: MappedWriteGuard<'a, ComponentData>, } -impl<'a, ComponentT: Component> HandleMut<'a, ComponentT> +impl<'comp, ComponentData: 'static> HandleMut<'comp, ComponentData> { - pub(crate) fn new(inner: WriteGuard<'a, Box<dyn Component>>) -> Self + /// Creates a new handle instance from a [`EntityComponentRef`]. + /// + /// # Errors + /// Will return `Err` if acquiring the component's lock fails. + pub fn from_entity_component_ref( + entity_component_ref: EntityComponentRef<'comp>, + ) -> Result<Self, HandleError> + { + Ok(Self::new( + entity_component_ref + .component() + .write_nonblock() + .map_err(AcquireLockError)?, + )) + } + + pub(crate) fn new(inner: WriteGuard<'comp, Box<dyn Any>>) -> Self { Self { inner: inner.map(|component| { - let component_type_name = component.type_name(); - - component.downcast_mut::<ComponentT>().unwrap_or_else(|| { - panic!( - "Cannot downcast component {component_type_name} to type {}", - type_name::<ComponentT>() - ); - }) + component + .downcast_mut::<ComponentData>() + .unwrap_or_else(|| { + panic!( + "Failed to downcast component to type {}", + type_name::<ComponentData>() + ); + }) }), } } } -impl<'component, ComponentT: Component> FromLockedOptional<'component> - for HandleMut<'component, ComponentT> -{ - fn from_locked_optional_component( - optional_component: Option<&'component Lock<Box<dyn Component>>>, - _world: &'component World, - ) -> Result<Self, LockError> - { - let component = optional_component.unwrap_or_else(|| { - panic!( - "Component {} was not found in entity", - type_name::<ComponentT>() - ); - }); - - Ok(Self::new(component.write_nonblock()?)) - } -} - -impl<'comp, ComponentT> FromLockedOptional<'comp> for Option<HandleMut<'comp, ComponentT>> -where - ComponentT: Component, -{ - fn from_locked_optional_component( - optional_component: Option<&'comp Lock<Box<dyn Component>>>, - _world: &'comp World, - ) -> Result<Self, LockError> - { - optional_component - .map(|lock| Ok(HandleMut::new(lock.write_nonblock()?))) - .transpose() - } -} - -impl<ComponentT: Component> Deref for HandleMut<'_, ComponentT> +impl<ComponentData: 'static> Deref for HandleMut<'_, ComponentData> { - type Target = ComponentT; + type Target = ComponentData; fn deref(&self) -> &Self::Target { @@ -361,7 +172,7 @@ impl<ComponentT: Component> Deref for HandleMut<'_, ComponentT> } } -impl<ComponentT: Component> DerefMut for HandleMut<'_, ComponentT> +impl<ComponentData: 'static> DerefMut for HandleMut<'_, ComponentData> { fn deref_mut(&mut self) -> &mut Self::Target { @@ -369,53 +180,32 @@ impl<ComponentT: Component> DerefMut for HandleMut<'_, ComponentT> } } +#[derive(Debug, thiserror::Error)] +pub enum HandleError +{ + #[error(transparent)] + AcquireLockFailed(#[from] AcquireLockError), +} + +#[derive(Debug, thiserror::Error)] +#[error("Failed to acquire component lock")] +pub struct AcquireLockError(#[source] LockError); + macro_rules! inner { ($c: tt) => { seq!(I in 0..=$c { - impl<#(IntoComp~I,)*> Sequence for (#(IntoComp~I,)*) - where - #( - for<'comp> IntoComp~I: Into<Component: Component>, - )* + impl<#(IntoCompParts~I: IntoParts,)*> Sequence for (#(IntoCompParts~I,)*) { const COUNT: usize = $c + 1; - type Array = [(Uid, Box<dyn Component>); $c + 1]; + type PartsArray = [Parts; $c + 1]; - fn into_array(self) -> Self::Array + fn into_parts_array(self) -> Self::PartsArray { [#({ - let (id, component) = self.I.into_component(); - - (id, Box::new(component)) + self.I.into_parts() },)*] } - - fn metadata() -> impl Array<Metadata> - { - [ - #( - Metadata { - id: IntoComp~I::Component::id(), - is_optional: IntoComp~I::Component::is_optional(), - }, - )* - ] - } - - fn added_event_ids() -> Vec<Uid> - { - vec![ - #(ComponentAddedEvent::<IntoComp~I::Component>::id(),)* - ] - } - - fn removed_event_ids() -> Vec<Uid> - { - vec![ - #(ComponentRemovedEvent::<IntoComp~I::Component>::id(),)* - ] - } } }); }; @@ -427,46 +217,134 @@ seq!(C in 0..=16 { impl Sequence for () { - type Array = [(Uid, Box<dyn Component>); 0]; + type PartsArray = [Parts; 0]; const COUNT: usize = 0; - fn into_array(self) -> Self::Array + fn into_parts_array(self) -> Self::PartsArray { [] } +} + +pub trait IntoParts +{ + fn into_parts(self) -> Parts; +} - fn metadata() -> impl Array<Metadata> +impl<ComponentT> IntoParts for ComponentT +where + ComponentT: Component, +{ + fn into_parts(self) -> Parts { - [] + Parts::builder() + .name(type_name::<Self>()) + .build(Self::id(), self) + } +} + +/// The parts of a component. +#[derive(Debug)] +#[non_exhaustive] +pub struct Parts +{ + id: Uid, + name: &'static str, + data: Box<dyn Any>, +} + +impl Parts +{ + #[must_use] + pub fn id(&self) -> Uid + { + self.id + } + + #[must_use] + pub fn name(&self) -> &'static str + { + self.name + } + + #[must_use] + pub fn builder() -> PartsBuilder + { + PartsBuilder::default() } - fn added_event_ids() -> Vec<Uid> + pub(crate) fn into_data(self) -> Box<dyn Any> + { + self.data + } +} + +#[derive(Debug)] +pub struct PartsBuilder +{ + name: &'static str, +} + +impl PartsBuilder +{ + #[must_use] + pub fn name(mut self, name: &'static str) -> Self { - Vec::new() + self.name = name; + self } - fn removed_event_ids() -> Vec<Uid> + #[must_use] + pub fn build<Data: 'static>(self, id: Uid, data: Data) -> Parts { - Vec::new() + Parts { + id, + name: self.name, + data: Box::new(data), + } } } -pub trait Into +impl Default for PartsBuilder { - type Component; + fn default() -> Self + { + Self { name: "(unspecified)" } + } +} - fn into_component(self) -> (Uid, Self::Component); +/// Pending component removals for a entity. +#[derive(Debug, Clone, Component)] +pub struct Removals +{ + component_ids: HashSet<Uid>, } -impl<ComponentT> Into for ComponentT -where - ComponentT: Component, +impl Removals { - type Component = Self; + pub fn contains<ComponentT: Component>(&self) -> bool + { + self.contains_id(ComponentT::id()) + } + + pub fn contains_id(&self, component_id: Uid) -> bool + { + self.component_ids.contains(&component_id) + } + + pub(crate) fn add_ids(&mut self, ids: impl IntoIterator<Item = Uid>) + { + self.component_ids.extend(ids) + } +} - fn into_component(self) -> (Uid, Self::Component) +impl FromIterator<Uid> for Removals +{ + fn from_iter<T: IntoIterator<Item = Uid>>(iter: T) -> Self { - (Self::id(), self) + Self { + component_ids: iter.into_iter().collect(), + } } } diff --git a/ecs/src/component/storage.rs b/ecs/src/component/storage.rs index 40909fb..b27b552 100644 --- a/ecs/src/component/storage.rs +++ b/ecs/src/component/storage.rs @@ -1,4 +1,4 @@ -use std::any::type_name; +use std::any::Any; use std::array::IntoIter as ArrayIter; use std::cell::RefCell; use std::vec::IntoIter as VecIntoIter; @@ -17,8 +17,6 @@ use crate::component::storage::graph::{ ArchetypeEdges, Graph, }; -use crate::component::Component; -use crate::type_name::TypeName; use crate::uid::{Kind as UidKind, Uid}; use crate::util::{BorrowedOrOwned, Either, StreamingIterator, VecExt}; @@ -35,14 +33,43 @@ pub struct ArchetypeSearchTerms<'a> impl ArchetypeSearchTerms<'_> { - fn excluded_contains(&self, uid: Uid) -> bool + fn excluded_contains(&self, comp_id: Uid) -> bool { - self.excluded_components.binary_search(&uid).is_ok() + let comp_id_kind = comp_id.kind(); + + debug_assert!( + comp_id_kind == UidKind::Component + || (comp_id_kind == UidKind::Pair + && comp_id.target_component() != Uid::wildcard()) + ); + + let is_found = self.excluded_components.binary_search(&comp_id).is_ok(); + + if !is_found && comp_id_kind == UidKind::Pair { + return self.excluded_components.iter().any(|excluded_comp_id| { + excluded_comp_id.kind() == UidKind::Pair + && excluded_comp_id.has_same_relation_as(comp_id) + && excluded_comp_id.target_component() == Uid::wildcard() + }); + } + + is_found + } + + fn contains_conflicting(&self) -> bool + { + self.excluded_components.iter().any(|excluded_comp_id| { + self.required_components + .binary_search(excluded_comp_id) + .is_ok() + }) } - fn required_contains(&self, uid: Uid) -> bool + fn archetype_contains_all_required(&self, archetype: &Archetype) -> bool { - self.required_components.binary_search(&uid).is_ok() + self.required_components + .iter() + .all(|comp_id| archetype.contains_matching_component(*comp_id)) } } @@ -61,13 +88,9 @@ impl Storage search_terms: ArchetypeSearchTerms<'search_terms>, ) -> ArchetypeRefIter<'_, 'search_terms> { - let archetype_id = ArchetypeId::new(&search_terms.required_components); + let archetype_id = ArchetypeId::new(search_terms.required_components); - if search_terms - .excluded_components - .iter() - .any(|excluded_comp_id| search_terms.required_contains(*excluded_comp_id)) - { + if search_terms.contains_conflicting() { return ArchetypeRefIter { storage: self, pre_iter: Either::B(Vec::new().into_iter()), @@ -82,8 +105,21 @@ impl Storage self.imaginary_archetypes .borrow_mut() .push(ImaginaryArchetype { - id: archetype_id, - component_ids: search_terms.required_components.to_vec(), + id: ArchetypeId::new(search_terms.required_components.iter().filter( + |required_comp_id| { + required_comp_id.kind() != UidKind::Pair + || required_comp_id.target_component() != Uid::wildcard() + }, + )), + component_ids: search_terms + .required_components + .iter() + .copied() + .filter(|required_comp_id| { + required_comp_id.kind() != UidKind::Pair + || required_comp_id.target_component() != Uid::wildcard() + }) + .collect(), }); let found_archetypes = self.find_all_archetype_with_comps(&search_terms); @@ -117,7 +153,7 @@ impl Storage return Err(Error::EntityAlreadyExists(uid)); } - let empty_archetype_id = ArchetypeId::from_components_metadata(&[]); + let empty_archetype_id = ArchetypeId::new_empty(); let archetype_node = self.graph.get_or_create_node(empty_archetype_id, &[]); @@ -161,16 +197,9 @@ impl Storage pub fn add_entity_component( &mut self, entity_uid: Uid, - component: (Uid, Box<dyn Component>), + (component_id, component_name, component): (Uid, &'static str, Box<dyn Any>), ) -> Result<(), Error> { - let (component_id, component) = component; - - debug_assert!( - !component.self_is_optional(), - "Adding a optional component to a entity is not supported" - ); - let Some(archetype_id) = self.entity_archetype_lookup.get(&entity_uid) else { return Err(Error::EntityDoesNotExist(entity_uid)); }; @@ -184,7 +213,7 @@ impl Storage if archetype_node .archetype() - .has_component_with_id(component_id) + .contains_component_with_exact_id(component_id) { return Err(Error::ComponentAlreadyInEntity { entity: entity_uid, @@ -192,56 +221,36 @@ impl Storage }); } - let add_edge_archetype_id = match archetype_node + let add_edge_archetype_id = if let Some(add_edge_id) = archetype_node .get_or_insert_edges(component_id, ArchetypeEdges::default) .add { - 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 + if !self.graph.contains_archetype(add_edge_id) { + let (_, add_edge_comp_ids) = self .graph - .get_node_by_id_mut(archetype_id) - .expect("Archetype should exist"); - - let (add_edge_id, add_edge_comp_ids) = - archetype_node.make_add_edge(component_id); + .get_node_by_id(archetype_id) + .expect("Archetype should exist") + .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 + self.graph.create_node(add_edge_id, &add_edge_comp_ids); } - }; - { - let add_edge_archetype_node = self + add_edge_id + } else { + let archetype_node = self .graph - .get_node_by_id_mut(add_edge_archetype_id) - .expect("Add edge archetype should exist"); + .get_node_by_id(archetype_id) + .expect("Archetype should exist"); - let add_edge_archetype_edges = add_edge_archetype_node - .get_or_insert_edges(component_id, ArchetypeEdges::default); + let (add_edge_id, add_edge_comp_ids) = + archetype_node.make_add_edge(component_id); - add_edge_archetype_edges.remove = Some(archetype_id); - } + if !self.graph.contains_archetype(add_edge_id) { + self.graph.create_node(add_edge_id, &add_edge_comp_ids); + } + + add_edge_id + }; let archetype_node = self .graph @@ -261,7 +270,7 @@ impl Storage entity.insert_component( component_id, - ArchetypeEntityComponent::new(component), + ArchetypeEntityComponent::new(component, component_id, component_name), add_edge_archetype, ); @@ -292,7 +301,7 @@ impl Storage if !archetype_node .archetype() - .has_component_with_id(component_id) + .contains_component_with_exact_id(component_id) { return Err(Error::ComponentNotFoundInEntity { entity: entity_uid, @@ -312,11 +321,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); @@ -367,9 +371,12 @@ impl Storage ) -> Vec<ArchetypeId> { let Some(mut search_iter) = - self.graph.dfs_archetype_add_edges(ArchetypeId::new(&[])) + self.graph.dfs_archetype_add_edges(ArchetypeId::new_empty()) else { // If the root archetype doesn't exist, no other archetype can exist either + // + // TODO: The above comment is not true. Cases where imaginary archetypes have + // been created should be handled as well return Vec::new(); }; @@ -398,11 +405,7 @@ impl Storage continue; } - if !search_terms - .required_components - .iter() - .all(|comp_id| node.archetype().has_component_with_id(*comp_id)) - { + if !search_terms.archetype_contains_all_required(node.archetype()) { continue; } @@ -415,14 +418,6 @@ impl Storage } } -impl TypeName for Storage -{ - fn type_name(&self) -> &'static str - { - type_name::<Self>() - } -} - #[cfg(feature = "vizoxide")] impl Storage { @@ -602,8 +597,7 @@ pub struct ArchetypeRefIter<'storage, 'search_terms> search_terms: ArchetypeSearchTerms<'search_terms>, } -impl<'component_storage, 'search_terms> Iterator - for ArchetypeRefIter<'component_storage, 'search_terms> +impl<'component_storage> Iterator for ArchetypeRefIter<'component_storage, '_> { type Item = &'component_storage Archetype; @@ -656,10 +650,7 @@ impl<'component_storage, 'search_terms> Iterator self.storage.imaginary_archetypes.borrow_mut().push( ImaginaryArchetype { id: add_edge_archetype_id, - component_ids: add_edge_archetype_comps - .iter() - .map(|comp_id| *comp_id) - .collect::<Vec<_>>(), + component_ids: add_edge_archetype_comps.clone(), }, ); @@ -673,8 +664,6 @@ impl<'component_storage, 'search_terms> Iterator )), found.into_iter(), )); - - continue; } _ => { unreachable!(); @@ -784,7 +773,7 @@ mod tests let archetype_node = new_storage .graph - .get_node_by_id(ArchetypeId::from_components_metadata(&[])) + .get_node_by_id(ArchetypeId::new_empty()) .expect("Archetype for entities with no component doesn't exist"); assert_eq!(archetype_node.archetype().component_cnt(), 0); @@ -792,7 +781,7 @@ mod tests assert_eq!( new_storage.entity_archetype_lookup.get(&uid).copied(), - Some(ArchetypeId::from_components_metadata(&[])) + Some(ArchetypeId::new_empty()) ); } } diff --git a/ecs/src/component/storage/archetype.rs b/ecs/src/component/storage/archetype.rs index 5306cf9..bb29701 100644 --- a/ecs/src/component/storage/archetype.rs +++ b/ecs/src/component/storage/archetype.rs @@ -1,12 +1,15 @@ +use std::any::Any; +use std::array::IntoIter as ArrayIntoIter; use std::hash::{DefaultHasher, Hash, Hasher}; +use std::iter::{Enumerate, Filter, Map, RepeatN, Zip}; +use std::option::IntoIter as OptionIntoIter; use std::slice::Iter as SliceIter; use hashbrown::HashMap; -use crate::component::{Component, Metadata as ComponentMetadata}; use crate::lock::Lock; use crate::uid::{Kind as UidKind, Uid}; -use crate::util::HashMapExt; +use crate::util::{Either, HashMapExt}; #[derive(Debug)] pub struct Archetype @@ -116,8 +119,54 @@ impl Archetype self.component_index_lookup.len() } + pub fn get_matching_component_indices( + &self, + component_id: Uid, + ) -> MatchingComponentIter + { + assert!( + component_id.kind() == UidKind::Component + || component_id.kind() == UidKind::Pair + ); + + if component_id.kind() == UidKind::Pair + && component_id.target_component() == Uid::wildcard() + { + return MatchingComponentIter { + inner: Either::A( + self.component_ids + .iter() + .enumerate() + .zip(std::iter::repeat_n(component_id, self.component_ids.len())) + .filter( + (|((_, other_comp_id), component_id)| { + other_comp_id.kind() == UidKind::Pair + && other_comp_id.has_same_relation_as(*component_id) + }) + as MatchingComponentIterFilterFn, + ) + .map(|((index, other_comp_id), _)| (*other_comp_id, index)), + ), + }; + } + + MatchingComponentIter { + inner: Either::B( + [component_id] + .into_iter() + .zip(self.get_index_for_component(component_id)), + ), + } + } + pub fn get_index_for_component(&self, component_id: Uid) -> Option<usize> { + assert!( + component_id.kind() == UidKind::Component + || (component_id.kind() == UidKind::Pair + && component_id.target_component() != Uid::wildcard()) + ); + self.component_index_lookup.get(&component_id).copied() } @@ -131,14 +180,70 @@ impl Archetype self.component_ids.iter().copied() } - pub fn has_component_with_id(&self, component_id: Uid) -> bool + pub fn contains_matching_component(&self, component_id: Uid) -> bool { - debug_assert_eq!(component_id.kind(), UidKind::Component); + let component_id_kind = component_id.kind(); + + debug_assert!( + component_id_kind == UidKind::Component || component_id_kind == UidKind::Pair + ); + + if component_id.kind() == UidKind::Pair + && component_id.target_component() == Uid::wildcard() + { + return self.component_ids.iter().any(|other_comp_id| { + other_comp_id.kind() == UidKind::Pair + && other_comp_id.has_same_relation_as(component_id) + }); + } + + self.contains_component_with_exact_id(component_id) + } + + pub fn contains_component_with_exact_id(&self, component_id: Uid) -> bool + { + let component_id_kind = component_id.kind(); + + debug_assert!( + component_id_kind == UidKind::Component + || (component_id_kind == UidKind::Pair + && component_id.target_component() != Uid::wildcard()) + ); self.component_index_lookup.contains_key(&component_id) } } +type MatchingComponentIterFilterFn = fn(&((usize, &Uid), Uid)) -> bool; + +type MatchingComponentIterMapFn = fn(((usize, &Uid), Uid)) -> (Uid, usize); + +type InnerMatchingComponentIterA<'archetype> = Map< + Filter< + Zip<Enumerate<SliceIter<'archetype, Uid>>, RepeatN<Uid>>, + MatchingComponentIterFilterFn, + >, + MatchingComponentIterMapFn, +>; + +type InnerMatchingComponentIterB = Zip<ArrayIntoIter<Uid, 1>, OptionIntoIter<usize>>; + +#[derive(Debug)] +pub struct MatchingComponentIter<'archetype> +{ + inner: Either<InnerMatchingComponentIterA<'archetype>, InnerMatchingComponentIterB>, +} + +impl Iterator for MatchingComponentIter<'_> +{ + type Item = (Uid, usize); + + fn next(&mut self) -> Option<Self::Item> + { + self.inner.next() + } +} + #[derive(Debug)] pub struct EntityIter<'archetype> { @@ -209,26 +314,31 @@ impl Entity #[derive(Debug)] pub struct EntityComponent { - name: &'static str, - component: Lock<Box<dyn Component>>, + id: Uid, + component: Lock<Box<dyn Any>>, } impl EntityComponent { - pub fn new(component: Box<dyn Component>) -> Self + pub fn new( + component: Box<dyn Any>, + component_id: Uid, + component_name: &'static str, + ) -> Self { Self { - name: component.type_name(), - component: Lock::new(component), + id: component_id, + component: Lock::new(component, component_name), } } - pub fn name(&self) -> &str + #[allow(dead_code)] + pub fn id(&self) -> Uid { - self.name + self.id } - pub fn component(&self) -> &Lock<Box<dyn Component>> + pub fn component(&self) -> &Lock<Box<dyn Any>> { &self.component } @@ -243,56 +353,33 @@ pub struct Id impl Id { - pub fn new(component_ids: &impl AsRef<[Uid]>) -> Self + pub fn new_empty() -> Self { - if component_ids.as_ref().is_empty() { - return Self { hash: 0 }; - } - - debug_assert!( - component_ids.as_ref().is_sorted(), - "Cannot create archetype ID from unsorted component IDs" - ); - - let mut hasher = DefaultHasher::new(); - - for component_id in component_ids.as_ref() { - component_id.hash(&mut hasher); - } - - Self { hash: hasher.finish() } + Self { hash: 0 } } - pub fn from_components_metadata<'a>( - components_metadata: impl IntoIterator<Item = &'a ComponentMetadata>, - ) -> Self + pub fn new<'a>(component_ids: impl IntoIterator<Item = &'a Uid>) -> Self { let mut hasher = DefaultHasher::new(); let mut prev_component_id: Option<Uid> = None; - let mut comp_metadata_iter = components_metadata.into_iter().peekable(); + let mut component_id_iter = component_ids.into_iter().peekable(); - if comp_metadata_iter.peek().is_none() { - return Self { hash: 0 }; + if component_id_iter.peek().is_none() { + return Self::new_empty(); } - for comp_metadata in comp_metadata_iter { - if prev_component_id - .is_some_and(|prev_comp_id| comp_metadata.id < prev_comp_id) - { + for comp_id in component_id_iter { + if prev_component_id.is_some_and(|prev_comp_id| *comp_id < prev_comp_id) { panic!( "Cannot create archetype ID from a unsorted component metadata list" ); } - prev_component_id = Some(comp_metadata.id); - - if comp_metadata.is_optional { - continue; - } + prev_component_id = Some(*comp_id); - comp_metadata.id.hash(&mut hasher); + comp_id.hash(&mut hasher); } Self { hash: hasher.finish() } diff --git a/ecs/src/component/storage/graph.rs b/ecs/src/component/storage/graph.rs index 11160e7..29fa937 100644 --- a/ecs/src/component/storage/graph.rs +++ b/ecs/src/component/storage/graph.rs @@ -140,19 +140,31 @@ impl Graph } fn create_missing_subset_node_edges( - target_node: &ArchetypeNode, + target_node: &mut ArchetypeNode, subset_node: &mut ArchetypeNode, ) { let uniq_comp_id = target_node .archetype() .component_ids_sorted() - .find(|id| !subset_node.archetype().has_component_with_id(*id)) + .find(|id| { + !subset_node + .archetype() + .contains_component_with_exact_id(*id) + }) .unwrap(); 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( @@ -169,7 +181,7 @@ impl Graph .find(|other_archetype_comp_id| { !target_node .archetype() - .has_component_with_id(*other_archetype_comp_id) + .contains_component_with_exact_id(*other_archetype_comp_id) }) .or_else(|| { if target_node.archetype().component_cnt() != 0 { @@ -196,7 +208,11 @@ impl Graph let extra_comp_id = superset_node .archetype() .component_ids_unsorted() - .find(|comp_id| !target_node.archetype().has_component_with_id(*comp_id)) + .find(|comp_id| { + !target_node + .archetype() + .contains_component_with_exact_id(*comp_id) + }) .expect("Archetype should contain one extra component ID"); superset_node @@ -234,7 +250,10 @@ impl ArchetypeNode insert_fn: impl FnOnce() -> ArchetypeEdges, ) -> &mut ArchetypeEdges { - debug_assert_eq!(component_id.kind(), UidKind::Component); + debug_assert!(matches!( + component_id.kind(), + UidKind::Component | UidKind::Pair + )); self.edges.entry(component_id).or_insert_with(insert_fn) } @@ -245,13 +264,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/entity.rs b/ecs/src/entity.rs index a43f9ce..bab3d61 100644 --- a/ecs/src/entity.rs +++ b/ecs/src/entity.rs @@ -1,10 +1,22 @@ +use std::any::type_name; + use linkme::distributed_slice; -use crate::component::storage::archetype::{Archetype, Entity as ArchetypeEntity}; -use crate::uid::Uid; +use crate::component::storage::archetype::{ + Archetype, + Entity as ArchetypeEntity, + MatchingComponentIter as ArchetypeMatchingComponentIter, +}; +use crate::component::{ + Component, + Handle as ComponentHandle, + HandleMut as ComponentHandleMut, +}; +use crate::uid::{Kind as UidKind, Uid}; use crate::{EntityComponentRef, World}; /// A handle to a entity. +#[derive(Debug)] pub struct Handle<'a> { archetype: &'a Archetype, @@ -21,15 +33,72 @@ impl<'a> Handle<'a> self.entity.uid() } + /// Returns a reference to the specified component in this entity. `None` is + /// returned if the component isn't found in the entity. + /// + /// # Panics + /// Will panic if: + /// - The component's ID is not a component ID + /// - The component is mutably borrowed elsewhere + #[must_use] + pub fn get<ComponentT: Component>(&self) -> Option<ComponentHandle<'_, ComponentT>> + { + assert_eq!(ComponentT::id().kind(), UidKind::Component); + + let component = self.get_matching_components(ComponentT::id()).next()?; + + Some( + ComponentHandle::from_entity_component_ref(component).unwrap_or_else(|err| { + panic!( + "Taking component {} lock failed: {err}", + type_name::<ComponentT>() + ); + }), + ) + } + + /// Returns a mutable reference to the specified component in this entity. `None` is + /// returned if the component isn't found in the entity. + /// + /// # Panics + /// Will panic if: + /// - The component's ID is not a component ID + /// - The component is borrowed elsewhere + #[must_use] + pub fn get_mut<ComponentT: Component>( + &self, + ) -> Option<ComponentHandleMut<'_, ComponentT>> + { + assert_eq!(ComponentT::id().kind(), UidKind::Component); + + let component = self.get_matching_components(ComponentT::id()).next()?; + + Some( + ComponentHandleMut::from_entity_component_ref(component).unwrap_or_else( + |err| { + panic!( + "Taking component {} lock failed: {err}", + type_name::<ComponentT>() + ); + }, + ), + ) + } + #[inline] #[must_use] - pub fn get_component(&self, component_uid: Uid) -> Option<EntityComponentRef<'a>> + pub fn get_matching_components(&self, component_uid: Uid) + -> MatchingComponentIter<'a> { - let index = self.archetype.get_index_for_component(component_uid)?; + MatchingComponentIter { + inner: self.archetype.get_matching_component_indices(component_uid), + entity: self.entity, + } + } - Some(EntityComponentRef::new( - self.entity.components().get(index).unwrap(), - )) + pub fn component_ids(&self) -> impl Iterator<Item = Uid> + '_ + { + self.archetype.component_ids_sorted() } pub(crate) fn new(archetype: &'a Archetype, entity: &'a ArchetypeEntity) -> Self @@ -38,6 +107,28 @@ impl<'a> Handle<'a> } } +#[derive(Debug)] +pub struct MatchingComponentIter<'a> +{ + inner: ArchetypeMatchingComponentIter<'a>, + entity: &'a ArchetypeEntity, +} + +impl<'a> Iterator for MatchingComponentIter<'a> +{ + type Item = EntityComponentRef<'a>; + + fn next(&mut self) -> Option<Self::Item> + { + let (matching_component_id, index) = self.inner.next()?; + + Some(EntityComponentRef::new( + matching_component_id, + self.entity.components().get(index).unwrap(), + )) + } +} + #[allow(clippy::module_name_repetitions)] #[macro_export] macro_rules! static_entity { @@ -55,7 +146,7 @@ macro_rules! static_entity { $crate::entity::CREATE_STATIC_ENTITIES )] #[linkme(crate=$crate::private::linkme)] - static CREATE_STATIC_ENTITY: fn(&$crate::World) = |world| { + static CREATE_STATIC_ENTITY: fn(&mut $crate::World) = |world| { world.create_entity_with_uid($components, *$ident); }; } @@ -65,4 +156,4 @@ macro_rules! static_entity { #[distributed_slice] #[doc(hidden)] -pub static CREATE_STATIC_ENTITIES: [fn(&World)]; +pub static CREATE_STATIC_ENTITIES: [fn(&mut World)]; diff --git a/ecs/src/event/component.rs b/ecs/src/event/component.rs index b4edffc..72a78a3 100644 --- a/ecs/src/event/component.rs +++ b/ecs/src/event/component.rs @@ -1,84 +1,12 @@ //! Component events. -use std::fmt::{Debug, Formatter}; -use std::marker::PhantomData; +use std::convert::Infallible; +use std::fmt::Debug; -use ecs_macros::Component; +use crate::Component; -use crate::component::Component; - -/// Event emitted when: -/// a) A entity with component `ComponentT` is spawned. -/// b) A component `ComponentT` is added to a entity. -#[derive(Clone, Component)] -pub struct Added<ComponentT> -where - ComponentT: Component, -{ - _pd: PhantomData<ComponentT>, -} - -impl<ComponentT> Debug for Added<ComponentT> -where - ComponentT: Component, -{ - fn fmt(&self, formatter: &mut Formatter<'_>) -> std::fmt::Result - { - formatter - .debug_struct("Added") - .field("_pd", &self._pd) - .finish() - } -} - -impl<ComponentT> Default for Added<ComponentT> -where - ComponentT: Component, -{ - fn default() -> Self - { - Self { _pd: PhantomData } - } -} - -/// Event emitted when: -/// a) A `ComponentT` component is removed from a entity. -/// b) A entity with component `ComponentT` is despawned. -#[derive(Clone, Component)] -pub struct Removed<ComponentT> -where - ComponentT: Component, -{ - _pd: PhantomData<ComponentT>, -} - -impl<ComponentT> Debug for Removed<ComponentT> -where - ComponentT: Component, -{ - fn fmt(&self, formatter: &mut Formatter<'_>) -> std::fmt::Result - { - formatter - .debug_struct("Removed") - .field("_pd", &self._pd) - .finish() - } -} - -impl<ComponentT> Default for Removed<ComponentT> -where - ComponentT: Component, -{ - fn default() -> Self - { - Self { _pd: PhantomData } - } -} - -/// Specifies a kind of component event UID. -#[derive(Debug, Clone, Copy)] -#[non_exhaustive] -pub enum Kind -{ - Removed, -} +/// Pair relation for events emitted when: +/// a) A entity with the target component is spawned. +/// b) The target component is added to a entity. +#[derive(Debug, Component)] +pub struct Added(Infallible); diff --git a/ecs/src/lib.rs b/ecs/src/lib.rs index 3caaa6b..07b1cba 100644 --- a/ecs/src/lib.rs +++ b/ecs/src/lib.rs @@ -1,9 +1,10 @@ #![deny(clippy::all, clippy::pedantic)] -use std::any::{type_name, TypeId}; +use std::any::{type_name, Any, TypeId}; use std::cell::RefCell; use std::fmt::Debug; use std::mem::ManuallyDrop; +use std::rc::Rc; use std::sync::atomic::{AtomicBool, Ordering}; use std::sync::Arc; @@ -12,11 +13,18 @@ use hashbrown::HashMap; use crate::actions::Action; use crate::component::storage::archetype::EntityComponent as ArchetypeEntityComponent; use crate::component::storage::Storage as ComponentStorage; -use crate::component::{Component, Sequence as ComponentSequence}; -use crate::entity::CREATE_STATIC_ENTITIES; -use crate::event::component::Kind as ComponentEventKind; +use crate::component::{ + Component, + IntoParts, + Parts as ComponentParts, + Removals as ComponentRemovals, + Sequence as ComponentSequence, +}; +use crate::entity::{Handle as EntityHandle, CREATE_STATIC_ENTITIES}; +use crate::event::component::Added as ComponentAddedEvent; use crate::extension::{Collector as ExtensionCollector, Extension}; -use crate::lock::{Lock, WriteGuard}; +use crate::lock::Lock; +use crate::pair::{ChildOf, DependsOn, Pair}; use crate::phase::{Phase, START as START_PHASE}; use crate::query::flexible::Query as FlexibleQuery; use crate::query::term::Without; @@ -27,33 +35,31 @@ use crate::query::{ Terms as QueryTerms, TermsBuilderInterface, }; -use crate::relationship::{ChildOf, DependsOn, Relationship}; use crate::sole::Sole; use crate::stats::Stats; use crate::system::{System, SystemComponent}; -use crate::type_name::TypeName; -use crate::uid::{Kind as UidKind, Uid}; +use crate::uid::{Kind as UidKind, Uid, Wildcard}; pub mod actions; pub mod component; pub mod entity; pub mod event; pub mod extension; -pub mod lock; +pub mod pair; pub mod phase; pub mod query; -pub mod relationship; pub mod sole; pub mod stats; pub mod system; pub mod tuple; -pub mod type_name; pub mod uid; pub mod util; #[doc(hidden)] pub mod private; +mod lock; + pub use ecs_macros::{Component, Sole}; pub use crate::query::Query; @@ -80,16 +86,13 @@ impl World world.add_sole(Stats::default()).ok(); for create_static_entity in CREATE_STATIC_ENTITIES { - create_static_entity(&world); + create_static_entity(&mut world); } world } /// Creates a new entity with the given components. - /// - /// # Panics - /// Will panic if mutable internal lock cannot be acquired. pub fn create_entity<Comps>(&mut self, components: Comps) -> Uid where Comps: ComponentSequence, @@ -103,29 +106,25 @@ impl World #[tracing::instrument(skip_all)] #[doc(hidden)] - pub fn create_entity_with_uid<Comps>(&self, components: Comps, entity_uid: Uid) + pub fn create_entity_with_uid<Comps>(&mut self, components: Comps, entity_uid: Uid) where Comps: ComponentSequence, { debug_assert_eq!(entity_uid.kind(), UidKind::Entity); - { - let mut component_storage_lock = self.lock_component_storage_rw(); - - if let Err(err) = component_storage_lock.create_entity(entity_uid) { - tracing::warn!("Failed to create entity: {err}"); - return; - }; - - Self::add_entity_components( - entity_uid, - components.into_array(), - &mut component_storage_lock, - ); + if let Err(err) = self.data.component_storage.create_entity(entity_uid) { + tracing::warn!("Failed to create entity: {err}"); + return; } - for added_event_id in Comps::added_event_ids() { - self.emit_event_by_id(added_event_id); + let added_component_ids = Self::add_entity_components( + entity_uid, + components.into_parts_array(), + &mut self.data.component_storage, + ); + + for comp_id in added_component_ids { + self.emit_event_by_id::<ComponentAddedEvent>(comp_id); } } @@ -148,27 +147,23 @@ impl World { self.create_entity(( SystemComponent { system: system.into_type_erased() }, - Relationship::<DependsOn, Phase>::new(phase_euid), + Pair::new::<DependsOn>(phase_euid), )); } - pub fn register_observer_system<'this, SystemImpl, Event>( + pub fn register_observer_system<'this, SystemImpl>( &'this mut self, system: impl System<'this, SystemImpl>, - event: Event, - ) where - Event: Component, + event: Pair<Uid, Uid>, + ) { - self.create_entity::<(SystemComponent, Event)>(( + self.create_entity(( SystemComponent { system: system.into_type_erased() }, event, )); } /// Adds a extensions. - /// - /// # Panics - /// Will panic if mutable internal lock cannot be acquired. pub fn add_extension(&mut self, extension: impl Extension) { let extension_collector = ExtensionCollector::new(self); @@ -184,19 +179,18 @@ 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) } /// Performs a single tick. - /// /// # Panics - /// Will panic if a internal lock cannot be acquired. - pub fn step(&self) -> StepResult + /// Will panic if mutable internal lock cannot be acquired. + pub fn step(&mut self) -> StepResult { if self.stop.load(Ordering::Relaxed) { return StepResult::Stop; @@ -212,11 +206,14 @@ impl World self.perform_phases(); - self.lock_component_storage_rw() - .create_imaginary_archetypes(); + self.data.component_storage.create_imaginary_archetypes(); + + let prev_pending_removals = std::mem::take(&mut self.data.pending_removals); self.perform_queued_actions(); + self.perform_removals(prev_pending_removals); + if self.stop.load(Ordering::Relaxed) { return StepResult::Stop; } @@ -239,10 +236,7 @@ impl World } /// Starts a loop which calls [`Self::step`] until the world is stopped. - /// - /// # Panics - /// Will panic if a internal lock cannot be acquired. - pub fn start_loop(&self) + pub fn start_loop(&mut self) { while let StepResult::Continue = self.step() {} } @@ -260,13 +254,7 @@ impl World VizoxideArchetypeGraphParams, }; - let component_storage_lock = self - .data - .component_storage - .read_nonblock() - .expect("Failed to acquire read-only component storage lock"); - - component_storage_lock.create_vizoxide_archetype_graph( + self.data.component_storage.create_vizoxide_archetype_graph( name, VizoxideArchetypeGraphParams { create_node_name: |archetype, _| { @@ -275,7 +263,7 @@ impl World archetype .component_ids_sorted() .into_iter() - .map(|comp_id| comp_id.id().to_string()) + .map(|comp_id| comp_id.to_string()) .collect::<Vec<_>>() .join(", ") )) @@ -302,16 +290,18 @@ impl World fn query_and_run_systems(&self, phase_euid: Uid) { - let system_comps_query = - self.query::<(&SystemComponent, &Relationship<DependsOn, Phase>), ()>(); - - let system_iter = system_comps_query.iter().filter(|(_, phase_rel)| { - phase_rel - .target_uids() - .any(|target_uid| target_uid == phase_euid) - }); + let system_query = self.flexible_query( + QueryTerms::<2>::builder() + .with_required([ + SystemComponent::id(), + Pair::new::<DependsOn>(phase_euid).id(), + ]) + .build(), + ); - for (system_component, _) in system_iter { + for (system_component,) in + QueryIter::<(&SystemComponent,), _>::new(self, system_query.iter()) + { // SAFETY: The world lives long enough unsafe { system_component.system.run(self); @@ -321,38 +311,37 @@ impl World fn perform_child_phases(&self, parent_phase_euid: Uid) { - let phase_query = self.query::<(&Phase, &Relationship<ChildOf, Phase>), ()>(); - - for (child_phase_euid, (_, phase_rel)) in phase_query.iter_with_euids() { - if !phase_rel - .target_uids() - .any(|phase_euid| phase_euid == parent_phase_euid) - { - continue; - } + let phase_query = self.flexible_query( + QueryTerms::<2>::builder() + .with_required([ + Phase::id(), + Pair::new::<ChildOf>(parent_phase_euid).id(), + ]) + .build(), + ); - self.query_and_run_systems(child_phase_euid); - self.perform_child_phases(child_phase_euid); + for child_phase_entity in &phase_query { + self.query_and_run_systems(child_phase_entity.uid()); + self.perform_child_phases(child_phase_entity.uid()); } } fn perform_phases(&self) { - let phase_query = - self.query::<(&Phase,), (Without<Relationship<ChildOf, Phase>>,)>(); + let phase_query = self.query::<(&Phase,), (Without<Pair<ChildOf, Wildcard>>,)>(); - for (phase_euid, (_,)) in phase_query.iter_with_euids() { - if phase_euid == *START_PHASE { + for (phase_entity_id, _) in phase_query.iter_with_euids() { + if phase_entity_id == *START_PHASE { continue; } - self.query_and_run_systems(phase_euid); - self.perform_child_phases(phase_euid); + self.query_and_run_systems(phase_entity_id); + self.perform_child_phases(phase_entity_id); } } #[tracing::instrument(skip_all)] - fn perform_queued_actions(&self) + fn perform_queued_actions(&mut self) { let mut active_action_queue = match *self.data.action_queue.active_queue.borrow() { @@ -369,92 +358,64 @@ impl World let mut has_swapped_active_queue = false; + // TODO: Figure out a good way to handle situations where there are multiple + // AddComponents/RemoveComponents actions that affect the same entity. for action in active_action_queue.drain(..) { match action { - Action::Spawn(components, component_added_event_ids) => { + Action::Spawn(components) => { + let new_entity_uid = Uid::new_unique(UidKind::Entity); + + if let Err(err) = + self.data.component_storage.create_entity(new_entity_uid) { - let mut component_storage_lock = self.lock_component_storage_rw(); - - let new_entity_uid = Uid::new_unique(UidKind::Entity); - - if let Err(err) = - component_storage_lock.create_entity(new_entity_uid) - { - tracing::warn!("Failed to create entity: {err}"); - continue; - }; - - Self::add_entity_components( - new_entity_uid, - components, - &mut component_storage_lock, - ); + tracing::warn!("Failed to create entity: {err}"); + continue; } + let added_component_ids = Self::add_entity_components( + new_entity_uid, + components, + &mut self.data.component_storage, + ); + if !has_swapped_active_queue { self.swap_event_queue(&mut has_swapped_active_queue); } - for comp_added_event_id in component_added_event_ids.ids { - self.emit_event_by_id(comp_added_event_id); + for comp_id in added_component_ids { + self.emit_event_by_id::<ComponentAddedEvent>(comp_id); } } Action::Despawn(entity_uid) => { - self.despawn_entity(entity_uid, &mut has_swapped_active_queue); + Self::schedule_removal( + &mut self.data.component_storage, + &mut self.data.pending_removals, + entity_uid, + PendingRemoval::Entity, + ); } - Action::AddComponents( - entity_uid, - components, - component_added_event_ids, - ) => { - { - let mut component_storage_lock = self.lock_component_storage_rw(); - - Self::add_entity_components( - entity_uid, - components, - &mut component_storage_lock, - ); - } + Action::AddComponents(entity_uid, components) => { + let added_component_ids = Self::add_entity_components( + entity_uid, + components, + &mut self.data.component_storage, + ); if !has_swapped_active_queue { self.swap_event_queue(&mut has_swapped_active_queue); } - // TODO: Fix that events are emitted for components that haven't been - // added because a error occurred (for example, the entity already has - // the component) - for comp_added_event_id in component_added_event_ids.ids { - self.emit_event_by_id(comp_added_event_id); + for comp_id in added_component_ids { + self.emit_event_by_id::<ComponentAddedEvent>(comp_id); } } - Action::RemoveComponents( - entity_uid, - components_metadata, - component_removed_event_ids, - ) => { - { - let mut component_storage_lock = self.lock_component_storage_rw(); - - Self::remove_entity_components( - entity_uid, - components_metadata - .iter() - .map(|comp_metadata| comp_metadata.id), - &mut component_storage_lock, - ); - } - - if !has_swapped_active_queue { - self.swap_event_queue(&mut has_swapped_active_queue); - } - - // TODO: Fix that events are emitted for components that haven't been - // removed because a error occurred (for example, the entity does not - // have the component) - for comp_removed_event_id in component_removed_event_ids.ids { - self.emit_event_by_id(comp_removed_event_id); - } + Action::RemoveComponents(entity_uid, component_ids) => { + Self::schedule_removal( + &mut self.data.component_storage, + &mut self.data.pending_removals, + entity_uid, + PendingRemoval::Components(component_ids), + ); } Action::Stop => { self.stop.store(true, Ordering::Relaxed); @@ -463,84 +424,128 @@ impl World } } - #[tracing::instrument(skip_all)] - fn despawn_entity(&self, entity_uid: Uid, has_swapped_active_queue: &mut bool) + fn perform_removals(&mut self, removals: Vec<(Uid, PendingRemoval)>) { - let mut component_storage_lock = self.lock_component_storage_rw(); - - let removed_entity = match component_storage_lock.remove_entity(entity_uid) { - Ok(components) => components, - Err(err) => { - tracing::error!("Failed to despawn entity: {err}"); - return; + for (entity_id, removal) in removals { + match removal { + PendingRemoval::Components(component_ids) => { + Self::remove_entity_components( + entity_id, + component_ids.into_iter().chain([ComponentRemovals::id()]), + &mut self.data.component_storage, + ); + } + PendingRemoval::Entity => { + if let Err(err) = self.data.component_storage.remove_entity(entity_id) + { + tracing::error!("Failed to remove entity {entity_id}: {err}"); + } + } } + } + } + + #[tracing::instrument(skip(component_storage, pending_removals))] + fn schedule_removal( + component_storage: &mut ComponentStorage, + pending_removals: &mut Vec<(Uid, PendingRemoval)>, + entity_uid: Uid, + removal: PendingRemoval, + ) + { + let Some(ent_handle) = Self::get_entity(component_storage, entity_uid) else { + tracing::warn!("Cannot schedule removal. Entity does not exist"); + return; }; - let component_removed_event_uids = removed_entity - .components() - .iter() - .map(|component| { - component - .component() - .read_nonblock() - .unwrap_or_else(|_| { - panic!( - "Failed to acquire read-only {} component lock", - component.name() - ) - }) - .get_event_uid(ComponentEventKind::Removed) - }) - .collect::<Vec<_>>(); - - drop(component_storage_lock); - - if !*has_swapped_active_queue { - self.swap_event_queue(has_swapped_active_queue); - } + let component_ids = match removal { + PendingRemoval::Components(ref component_ids) => component_ids, + PendingRemoval::Entity => &ent_handle.component_ids().collect::<Vec<_>>(), + }; - for comp_removed_event_id in component_removed_event_uids { - self.emit_event_by_id(comp_removed_event_id); - } + let Some(mut component_removals) = ent_handle.get_mut::<ComponentRemovals>() + else { + Self::add_entity_components( + entity_uid, + [ComponentRemovals::from_iter(component_ids.iter().copied()) + .into_parts()], + component_storage, + ); + + pending_removals.push((entity_uid, removal)); + + return; + }; + + component_removals.add_ids(component_ids.iter().copied()); + + drop(component_removals); + + pending_removals.push((entity_uid, removal)); } fn add_entity_components( entity_uid: Uid, - components: impl IntoIterator<Item = (Uid, Box<dyn Component>)>, + components: impl IntoIterator<Item = ComponentParts>, component_storage: &mut ComponentStorage, - ) + ) -> Vec<Uid> { - for (component_id, component) in components { - if let Err(err) = component_storage - .add_entity_component(entity_uid, (component_id, component)) - { + let component_iter = components.into_iter(); + + let mut added_component_ids = + Vec::<Uid>::with_capacity(component_iter.size_hint().0); + + for component_parts in component_iter { + let comp_id = component_parts.id(); + + if let Err(err) = component_storage.add_entity_component( + entity_uid, + (comp_id, component_parts.name(), component_parts.into_data()), + ) { tracing::error!("Failed to add component to entity: {err}"); + continue; } + + added_component_ids.push(comp_id); } + + added_component_ids } fn remove_entity_components( entity_uid: Uid, component_ids: impl IntoIterator<Item = Uid>, component_storage: &mut ComponentStorage, - ) + ) -> Vec<Uid> { - for component_id in component_ids { + let component_id_iter = component_ids.into_iter(); + + let mut removed_component_ids = + Vec::<Uid>::with_capacity(component_id_iter.size_hint().0); + + for component_id in component_id_iter { if let Err(err) = component_storage.remove_entity_component(entity_uid, component_id) { tracing::error!("Failed to remove component to entity: {err}"); + continue; } + + removed_component_ids.push(component_id); } + + removed_component_ids } - fn emit_event_by_id(&self, event_id: Uid) + fn emit_event_by_id<Event: Component>(&self, target: Uid) { - let mut query_required_ids = [SystemComponent::id(), event_id]; + if target.kind() == UidKind::Pair { + return; + } let query = self.flexible_query( - QueryTerms::builder() - .with_required_ids(&mut query_required_ids) + QueryTerms::<2>::builder() + .with_required([SystemComponent::id(), Pair::new::<Event>(target).id()]) .build(), ); @@ -563,12 +568,19 @@ impl World *has_swapped_active_queue = true; } - fn lock_component_storage_rw(&self) -> WriteGuard<'_, ComponentStorage> + fn get_entity( + component_storage: &mut ComponentStorage, + entity_uid: Uid, + ) -> Option<EntityHandle<'_>> { - self.data - .component_storage - .write_nonblock() - .expect("Failed to acquire read-write component storage lock") + let archetype = component_storage.get_entity_archetype(entity_uid)?; + + Some(EntityHandle::new( + archetype, + archetype + .get_entity_by_id(entity_uid) + .expect("Not possible"), + )) } } @@ -590,30 +602,58 @@ pub enum StepResult Stop, } -#[derive(Debug, Default)] -pub struct WorldData +#[derive(Debug)] +struct WorldData { - component_storage: Arc<Lock<ComponentStorage>>, + component_storage: ComponentStorage, sole_storage: SoleStorage, - action_queue: Arc<ActionQueue>, + action_queue: Rc<ActionQueue>, + pending_removals: Vec<(Uid, PendingRemoval)>, +} + +impl Default for WorldData +{ + fn default() -> Self + { + Self { + component_storage: ComponentStorage::default(), + sole_storage: SoleStorage::default(), + action_queue: Rc::new(ActionQueue::default()), + pending_removals: Vec::new(), + } + } +} + +#[derive(Debug)] +enum PendingRemoval +{ + Components(Vec<Uid>), + Entity, } #[derive(Debug)] pub struct EntityComponentRef<'a> { - comp: &'a ArchetypeEntityComponent, + component_id: Uid, + component: &'a ArchetypeEntityComponent, } impl<'a> EntityComponentRef<'a> { - pub fn component(&self) -> &'a Lock<Box<dyn Component>> + fn component(&self) -> &'a Lock<Box<dyn Any>> { - self.comp.component() + self.component.component() } - fn new(comp: &'a ArchetypeEntityComponent) -> Self + #[must_use] + pub fn id(&self) -> Uid { - Self { comp } + self.component_id + } + + fn new(component_id: Uid, comp: &'a ArchetypeEntityComponent) -> Self + { + Self { component_id, component: comp } } } @@ -625,7 +665,7 @@ enum ActiveActionQueue B, } -#[derive(Debug, Default)] +#[derive(Debug)] struct ActionQueue { queue_a: Lock<Vec<Action>>, @@ -652,11 +692,15 @@ impl ActionQueue } } -impl TypeName for ActionQueue +impl Default for ActionQueue { - fn type_name(&self) -> &'static str + fn default() -> Self { - type_name::<Self>() + Self { + queue_a: Lock::new(Vec::new(), type_name::<Vec<Action>>()), + queue_b: Lock::new(Vec::new(), type_name::<Vec<Action>>()), + active_queue: RefCell::new(ActiveActionQueue::default()), + } } } @@ -701,7 +745,7 @@ impl SoleStorage self.storage.insert( sole_type_id, ManuallyDrop::new(StoredSole { - sole: Arc::new(Lock::new(Box::new(sole))), + sole: Arc::new(Lock::new(Box::new(sole), type_name::<SoleT>())), drop_last, }), ); @@ -718,18 +762,9 @@ impl Drop for SoleStorage for sole in self.storage.values_mut() { if sole.drop_last { - tracing::trace!( - "Sole {} pushed to dropping last queue", - sole.sole.read_nonblock().unwrap().type_name() - ); - soles_to_drop_last.push(sole); continue; } - tracing::trace!( - "Dropping sole {}", - sole.sole.read_nonblock().unwrap().type_name() - ); unsafe { ManuallyDrop::drop(sole); @@ -737,11 +772,6 @@ impl Drop for SoleStorage } for sole in &mut soles_to_drop_last { - tracing::trace!( - "Dropping sole {} last", - sole.sole.read_nonblock().unwrap().type_name() - ); - unsafe { ManuallyDrop::drop(sole); } diff --git a/ecs/src/lock.rs b/ecs/src/lock.rs index d6ed40e..0b36922 100644 --- a/ecs/src/lock.rs +++ b/ecs/src/lock.rs @@ -9,23 +9,21 @@ use parking_lot::{ RwLockWriteGuard, }; -use crate::type_name::TypeName; - -#[derive(Debug, Default)] +#[derive(Debug)] pub struct Lock<Value> -where - Value: TypeName, { inner: RwLock<Value>, + value_type_name: &'static str, } impl<Value> Lock<Value> -where - Value: TypeName, { - pub fn new(value: Value) -> Self + pub fn new(value: Value, value_type_name: &'static str) -> Self { - Self { inner: RwLock::new(value) } + Self { + inner: RwLock::new(value), + value_type_name, + } } /// Tries to a acquire a handle to the resource with read access. @@ -36,9 +34,12 @@ where { let guard = self.inner.try_read().ok_or(Error::ReadUnavailable)?; - tracing::trace!("Acquired lock to value of type {}", guard.type_name()); + tracing::trace!("Acquired lock to value of type {}", self.value_type_name); - Ok(ReadGuard { inner: guard }) + Ok(ReadGuard { + inner: guard, + value_type_name: self.value_type_name, + }) } /// Tries to a acquire a handle to the resource with mutable access. @@ -51,15 +52,13 @@ where tracing::trace!( "Acquired mutable lock to value of type {}", - guard.type_name() + self.value_type_name ); - Ok(WriteGuard { inner: guard }) - } - - pub fn into_inner(self) -> Value - { - self.inner.into_inner() + Ok(WriteGuard { + inner: guard, + value_type_name: self.value_type_name, + }) } } @@ -75,23 +74,20 @@ pub enum Error #[derive(Debug)] pub struct ReadGuard<'guard, Value> -where - Value: TypeName, { inner: RwLockReadGuard<'guard, Value>, + value_type_name: &'static str, } impl<'guard, Value> ReadGuard<'guard, Value> -where - Value: TypeName, { pub fn map<NewValue>( self, func: impl FnOnce(&Value) -> &NewValue, ) -> MappedReadGuard<'guard, NewValue> - where - NewValue: TypeName, { + let value_type_name = self.value_type_name; + // The 'inner' field cannot be moved out of ReadGuard in a normal way since // ReadGuard implements Drop let inner = unsafe { std::ptr::read(&self.inner) }; @@ -99,13 +95,12 @@ where MappedReadGuard { inner: RwLockReadGuard::map(inner, func), + value_type_name, } } } impl<Value> Deref for ReadGuard<'_, Value> -where - Value: TypeName, { type Target = Value; @@ -116,26 +111,21 @@ where } impl<Value> Drop for ReadGuard<'_, Value> -where - Value: TypeName, { fn drop(&mut self) { - tracing::trace!("Dropped lock to value of type {}", self.type_name()); + tracing::trace!("Dropped lock to value of type {}", self.value_type_name); } } #[derive(Debug)] pub struct MappedReadGuard<'guard, Value> -where - Value: TypeName, { inner: MappedRwLockReadGuard<'guard, Value>, + value_type_name: &'static str, } impl<Value> Deref for MappedReadGuard<'_, Value> -where - Value: TypeName, { type Target = Value; @@ -146,34 +136,32 @@ where } impl<Value> Drop for MappedReadGuard<'_, Value> -where - Value: TypeName, { fn drop(&mut self) { - tracing::trace!("Dropped mapped lock to value of type {}", self.type_name()); + tracing::trace!( + "Dropped mapped lock to value of type {}", + self.value_type_name + ); } } #[derive(Debug)] pub struct WriteGuard<'guard, Value> -where - Value: TypeName, { inner: RwLockWriteGuard<'guard, Value>, + value_type_name: &'static str, } impl<'guard, Value> WriteGuard<'guard, Value> -where - Value: TypeName, { pub fn map<NewValue>( self, func: impl FnOnce(&mut Value) -> &mut NewValue, ) -> MappedWriteGuard<'guard, NewValue> - where - NewValue: TypeName, { + let value_type_name = self.value_type_name; + // The 'inner' field cannot be moved out of ReadGuard in a normal way since // ReadGuard implements Drop let inner = unsafe { std::ptr::read(&self.inner) }; @@ -181,13 +169,12 @@ where MappedWriteGuard { inner: RwLockWriteGuard::map(inner, func), + value_type_name, } } } impl<Value> Deref for WriteGuard<'_, Value> -where - Value: TypeName, { type Target = Value; @@ -198,8 +185,6 @@ where } impl<Value> DerefMut for WriteGuard<'_, Value> -where - Value: TypeName, { fn deref_mut(&mut self) -> &mut Self::Target { @@ -208,26 +193,24 @@ where } impl<Value> Drop for WriteGuard<'_, Value> -where - Value: TypeName, { fn drop(&mut self) { - tracing::trace!("Dropped mutable lock to value of type {}", self.type_name()); + tracing::trace!( + "Dropped mutable lock to value of type {}", + self.value_type_name + ); } } #[derive(Debug)] pub struct MappedWriteGuard<'guard, Value> -where - Value: TypeName, { inner: MappedRwLockWriteGuard<'guard, Value>, + value_type_name: &'static str, } impl<Value> Deref for MappedWriteGuard<'_, Value> -where - Value: TypeName, { type Target = Value; @@ -238,8 +221,6 @@ where } impl<Value> DerefMut for MappedWriteGuard<'_, Value> -where - Value: TypeName, { fn deref_mut(&mut self) -> &mut Self::Target { @@ -248,14 +229,12 @@ where } impl<Value> Drop for MappedWriteGuard<'_, Value> -where - Value: TypeName, { fn drop(&mut self) { tracing::trace!( "Dropped mapped mutable lock to value of type {}", - self.type_name() + self.value_type_name ); } } diff --git a/ecs/src/pair.rs b/ecs/src/pair.rs new file mode 100644 index 0000000..4ff4995 --- /dev/null +++ b/ecs/src/pair.rs @@ -0,0 +1,198 @@ +use std::convert::Infallible; + +use crate::component::{IntoParts as IntoComponentParts, Parts as ComponentParts}; +use crate::entity::{ + Handle as EntityHandle, + MatchingComponentIter as EntityMatchingComponentIter, +}; +use crate::query::{ + TermWithField as QueryTermWithField, + TermsBuilder as QueryTermsBuilder, + TermsBuilderInterface, +}; +use crate::uid::{PairParams as UidPairParams, Uid, Wildcard, With as WithUid}; +use crate::{Component, World}; + +#[derive(Debug)] +pub struct Pair<RelationElem: Element, TargetElem: Element> +{ + relation: RelationElem, + target: TargetElem, +} + +impl Pair<Uid, Uid> +{ + #[must_use] + pub fn new<Relation: WithUid>(target: Uid) -> Self + { + Self { relation: Relation::uid(), target } + } + + #[must_use] + pub fn id(&self) -> Uid + { + Uid::new_pair(&UidPairParams { + relation: self.relation, + target: self.target, + }) + } +} + +impl IntoComponentParts for Pair<Uid, Uid> +{ + fn into_parts(self) -> ComponentParts + { + ComponentParts::builder().name("Pair").build(self.id(), ()) + } +} + +impl<Relation, Target> QueryTermWithField for Pair<Relation, Target> +where + Relation: WithUid, + Target: WithUid, +{ + type Field<'a> = Handle<'a>; + + fn apply_to_terms_builder<const MAX_TERM_CNT: usize>( + terms_builder: &mut QueryTermsBuilder<MAX_TERM_CNT>, + ) + { + terms_builder.with_required([Self::uid()]); + } + + fn get_field<'world>( + entity_handle: &EntityHandle<'world>, + world: &'world World, + ) -> Self::Field<'world> + { + let first_matching_comp = entity_handle + .get_matching_components(Self::uid()) + .next() + .expect("Not possible"); + + Handle { + world, + pair_uid: first_matching_comp.id(), + } + } +} + +impl<Relation, Target> WithUid for Pair<Relation, Target> +where + Relation: WithUid, + Target: WithUid, +{ + fn uid() -> Uid + { + Uid::new_pair(&UidPairParams { + relation: Relation::uid(), + target: Target::uid(), + }) + } +} + +impl<Relation> QueryTermWithField for &'static [Pair<Relation, Wildcard>] +where + Relation: WithUid, +{ + type Field<'a> = HandleIter<'a>; + + fn apply_to_terms_builder<const MAX_TERM_CNT: usize>( + terms_builder: &mut QueryTermsBuilder<MAX_TERM_CNT>, + ) + { + terms_builder.with_required([Pair::<Relation, Wildcard>::uid()]); + } + + fn get_field<'world>( + entity_handle: &EntityHandle<'world>, + world: &'world World, + ) -> Self::Field<'world> + { + HandleIter { + inner: entity_handle + .get_matching_components(Pair::<Relation, Wildcard>::uid()), + world, + } + } +} + +pub struct Handle<'world> +{ + world: &'world World, + pair_uid: Uid, +} + +impl Handle<'_> +{ + #[must_use] + pub fn get_target_entity(&self) -> Option<EntityHandle<'_>> + { + let archetype = self + .world + .data + .component_storage + .get_entity_archetype(self.pair_uid.target_entity())?; + + let Some(archetype_entity) = + archetype.get_entity_by_id(self.pair_uid.target_entity()) + else { + unreachable!(); + }; + + Some(EntityHandle::new(archetype, archetype_entity)) + } +} + +pub struct HandleIter<'a> +{ + inner: EntityMatchingComponentIter<'a>, + world: &'a World, +} + +impl<'a> Iterator for HandleIter<'a> +{ + type Item = Handle<'a>; + + fn next(&mut self) -> Option<Self::Item> + { + let matching_comp = self.inner.next()?; + + Some(Handle { + world: self.world, + pair_uid: matching_comp.id(), + }) + } +} + +pub trait Element: sealed::Sealed +{ + type Value; +} + +impl Element for Uid +{ + type Value = Uid; +} + +impl sealed::Sealed for Uid {} + +impl<WithUidT: WithUid> Element for WithUidT +{ + type Value = Infallible; +} + +impl<WithUidT: WithUid> sealed::Sealed for WithUidT {} + +/// Relation denoting a dependency to another entity +#[derive(Debug, Default, Clone, Copy, Component)] +pub struct DependsOn; + +/// Relation denoting being the child of another entity. +#[derive(Debug, Default, Clone, Copy, Component)] +pub struct ChildOf; + +mod sealed +{ + pub trait Sealed {} +} diff --git a/ecs/src/phase.rs b/ecs/src/phase.rs index b8660f2..9f47fb8 100644 --- a/ecs/src/phase.rs +++ b/ecs/src/phase.rs @@ -1,6 +1,6 @@ use ecs_macros::Component; -use crate::relationship::{ChildOf, Relationship}; +use crate::pair::{ChildOf, Pair}; use crate::static_entity; #[derive(Debug, Default, Clone, Copy, Component)] @@ -10,6 +10,4 @@ static_entity!(pub START, (Phase,)); static_entity!(pub PRE_UPDATE, (Phase,)); -static_entity!(pub UPDATE, (Phase, <Relationship<ChildOf, Phase>>::new(*PRE_UPDATE))); - -static_entity!(pub PRESENT, (Phase, <Relationship<ChildOf, Phase>>::new(*UPDATE))); +static_entity!(pub UPDATE, (Phase, Pair::new::<ChildOf>(*PRE_UPDATE))); diff --git a/ecs/src/query.rs b/ecs/src/query.rs index d7d2d1c..ccb7add 100644 --- a/ecs/src/query.rs +++ b/ecs/src/query.rs @@ -1,15 +1,19 @@ use std::any::type_name; -use std::borrow::Cow; use std::marker::PhantomData; use seq_macro::seq; -use crate::component::{Component, FromLockedOptional, Ref as ComponentRef}; +use crate::component::{ + Component, + Handle as ComponentHandle, + HandleMut as ComponentHandleMut, +}; 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::uid::{Kind as UidKind, Uid, With as WithUid}; +use crate::util::array_vec::ArrayVec; +use crate::util::Array; use crate::World; pub mod flexible; @@ -22,7 +26,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)>, } @@ -110,7 +115,7 @@ where impl<'query, 'world, FieldTerms, FieldlessTerms> IntoIterator for &'query Query<'world, FieldTerms, FieldlessTerms> where - FieldTerms: TermWithFieldTuple + 'world, + FieldTerms: TermWithFieldTuple, FieldlessTerms: TermWithoutFieldTuple, { type IntoIter = Iter<'query, 'world, FieldTerms, FlexibleQueryIter<'query>>; @@ -147,43 +152,51 @@ 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> +#[must_use] +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> +#[allow(clippy::return_self_not_must_use)] +pub trait TermsBuilderInterface { - fn with<ComponentT: Component>(self) -> Self; + fn with<WithUidT: WithUid>(self) -> Self; + + fn without<WithUidT: WithUid>(self) -> Self; - fn without<ComponentT: Component>(self) -> Self; + fn with_required(self, ids: impl Array<Uid>) -> Self; - fn with_required_ids(self, ids: &'a mut [Uid]) -> Self; + fn without_ids(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)* } }; @@ -191,74 +204,101 @@ macro_rules! impl_terms_builder { impl_terms_builder! { #[allow(unused_mut)] - fn with<ComponentT: Component>(mut self) -> Self + fn with<WithUidT: WithUid>(mut self) -> Self { - if ComponentT::is_optional() { - return self; - } + let insert_index = self.required_components + .partition_point(|id| *id <= WithUidT::uid()); self.required_components - .to_mut() - .insert_at_partition_point_by_key(ComponentT::id(), |id| *id); + .insert(insert_index, WithUidT::uid()); self } #[allow(unused_mut)] - fn without<ComponentT: Component>(mut self) -> Self + fn without<WithUidT: WithUid>(mut self) -> Self { - if ComponentT::is_optional() { - panic!( - "{}::without cannot take optional component", - type_name::<Self>() - ); - } + let insert_index = self.excluded_components + .partition_point(|id| *id <= WithUidT::uid()); self.excluded_components - .to_mut() - .insert_at_partition_point_by_key(ComponentT::id(), |id| *id); + .insert(insert_index, WithUidT::uid()); 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() { + if !ids.as_ref().is_sorted() { + ids.as_mut().sort(); + } + + if self.required_components.is_empty() { + self.required_components.extend(ids); return self; } - if !ids.is_sorted() { - ids.sort(); + let mut id_iter = ids.into_iter(); + + while let Some(id) = id_iter.next() { + let insert_index = self.required_components + .partition_point(|other_id| *other_id <= id); + + if insert_index == self.required_components.len() { + self.required_components.extend([id].into_iter().chain(id_iter)); + + return self; + } + + self.required_components + .insert(insert_index, id); + } - if self.required_components.is_empty() { - self.required_components = Cow::Borrowed(ids); + self + } + #[allow(unused_mut)] + fn without_ids(mut self, mut ids: impl Array<Uid>) -> Self + { + if !ids.as_ref().is_sorted() { + ids.as_mut().sort(); + } + + if self.excluded_components.is_empty() { + self.excluded_components.extend(ids); return self; } - let first_id_pp_index = self.required_components.partition_point(|req_comp_id| { - req_comp_id <= ids.first().expect("Cannot happend since not empty") - }); + let mut id_iter = ids.into_iter(); - let removed = self - .required_components - .to_mut() - .splice(first_id_pp_index..first_id_pp_index, ids.iter().copied()); + while let Some(id) = id_iter.next() { + let insert_index = self.excluded_components + .partition_point(|other_id| *other_id <= id); - assert_eq!(removed.count(), 0); + if insert_index == self.excluded_components.len() { + self.excluded_components.extend([id].into_iter().chain(id_iter)); + + return self; + } + + self.excluded_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> + #[must_use] + pub fn build(self) -> Terms<MAX_TERM_CNT> { - assert!(self.required_components.is_sorted()); - assert!(self.excluded_components.is_sorted()); + debug_assert!(self.required_components.is_sorted()); + debug_assert!(self.excluded_components.is_sorted()); Terms { required_components: self.required_components, @@ -269,14 +309,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>, @@ -284,30 +328,83 @@ pub trait TermWithField ) -> Self::Field<'world>; } -impl<ComponentRefT: ComponentRef> TermWithField for ComponentRefT +impl<ComponentT: Component> TermWithField for &ComponentT { - type Field<'a> = ComponentRefT::Handle<'a>; + type Field<'a> = ComponentHandle<'a, ComponentT>; - 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>(); + terms_builder.with::<ComponentT>(); } fn get_field<'world>( entity_handle: &EntityHandle<'world>, - world: &'world World, + _world: &'world World, ) -> Self::Field<'world> { - Self::Field::from_locked_optional_component( - entity_handle - .get_component(ComponentRefT::Component::id()) - .map(|component| component.component()), - world, - ) - .unwrap_or_else(|err| { + assert_eq!(ComponentT::id().kind(), UidKind::Component); + + let Some(component) = entity_handle + .get_matching_components(ComponentT::id()) + .next() + else { panic!( - "Taking component {} lock failed: {err}", - type_name::<ComponentRefT::Component>() + concat!( + "Component {} was not found in entity {}. There ", + "is most likely a bug in the entity querying" + ), + type_name::<ComponentT>(), + entity_handle.uid() + ); + }; + + Self::Field::from_entity_component_ref(component).unwrap_or_else(|err| { + panic!( + "Creating handle to component {} failed: {err}", + type_name::<ComponentT>() + ); + }) + } +} + +impl<ComponentT: Component> TermWithField for &mut ComponentT +{ + type Field<'a> = ComponentHandleMut<'a, ComponentT>; + + fn apply_to_terms_builder<const MAX_TERM_CNT: usize>( + terms_builder: &mut TermsBuilder<MAX_TERM_CNT>, + ) + { + terms_builder.with::<ComponentT>(); + } + + fn get_field<'world>( + entity_handle: &EntityHandle<'world>, + _world: &'world World, + ) -> Self::Field<'world> + { + assert_eq!(ComponentT::id().kind(), UidKind::Component); + + let Some(component) = entity_handle + .get_matching_components(ComponentT::id()) + .next() + else { + panic!( + concat!( + "Component {} was not found in entity {}. There ", + "is most likely a bug in the entity querying" + ), + type_name::<ComponentT>(), + entity_handle.uid() + ); + }; + + Self::Field::from_entity_component_ref(component).unwrap_or_else(|err| { + panic!( + "Creating handle to component {} failed: {err}", + type_name::<ComponentT>() ); }) } @@ -315,14 +412,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>, @@ -332,7 +433,7 @@ pub trait TermWithFieldTuple pub struct Iter<'query, 'world, FieldTerms, EntityHandleIter> where - FieldTerms: TermWithFieldTuple + 'world, + FieldTerms: TermWithFieldTuple, EntityHandleIter: Iterator<Item = EntityHandle<'query>>, { world: &'world World, @@ -343,7 +444,7 @@ where impl<'query, 'world, FieldTerms, EntityHandleIter> Iter<'query, 'world, FieldTerms, EntityHandleIter> where - FieldTerms: TermWithFieldTuple + 'world, + FieldTerms: TermWithFieldTuple, EntityHandleIter: Iterator<Item = EntityHandle<'query>>, 'world: 'query, { @@ -362,7 +463,7 @@ where impl<'query, 'world, FieldTerms, EntityHandleIter> Iterator for Iter<'query, 'world, FieldTerms, EntityHandleIter> where - FieldTerms: TermWithFieldTuple + 'world, + FieldTerms: TermWithFieldTuple, EntityHandleIter: Iterator<Item = EntityHandle<'query>>, 'world: 'query, { @@ -378,7 +479,7 @@ where pub struct ComponentAndEuidIter<'query, 'world, FieldTerms, EntityHandleIter> where - FieldTerms: TermWithFieldTuple + 'world, + FieldTerms: TermWithFieldTuple, EntityHandleIter: Iterator<Item = EntityHandle<'query>>, { world: &'world World, @@ -389,7 +490,7 @@ where impl<'query, 'world, FieldTerms, EntityHandleIter> Iterator for ComponentAndEuidIter<'query, 'world, FieldTerms, EntityHandleIter> where - FieldTerms: TermWithFieldTuple + 'world, + FieldTerms: TermWithFieldTuple, EntityHandleIter: Iterator<Item = EntityHandle<'query>>, 'world: 'query, { @@ -411,7 +512,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 +526,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 +553,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..add30b0 100644 --- a/ecs/src/query/flexible.rs +++ b/ecs/src/query/flexible.rs @@ -2,25 +2,20 @@ use std::iter::{repeat_n, FlatMap, RepeatN, Zip}; use crate::component::storage::archetype::{Archetype, EntityIter}; -use crate::component::storage::{ - ArchetypeRefIter, - ArchetypeSearchTerms, - Storage as ComponentStorage, -}; +use crate::component::storage::{ArchetypeRefIter, ArchetypeSearchTerms}; use crate::entity::Handle as EntityHandle; -use crate::lock::ReadGuard; use crate::query::Terms; 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>, + world: &'world World, + 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] @@ -28,6 +23,8 @@ impl<'world, 'terms> Query<'world, 'terms> { Iter { iter: self + .world + .data .component_storage .search_archetypes(ArchetypeSearchTerms { required_components: &self.terms.required_components, @@ -42,16 +39,20 @@ 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 - .data - .component_storage - .read_nonblock() - .expect("Failed to acquire read-only component storage lock"), - terms, - } + Self { world, terms } + } +} + +impl<'query, const MAX_TERM_CNT: usize> IntoIterator for &'query Query<'_, MAX_TERM_CNT> +{ + type IntoIter = Iter<'query>; + type Item = EntityHandle<'query>; + + fn into_iter(self) -> Self::IntoIter + { + self.iter() } } diff --git a/ecs/src/query/term.rs b/ecs/src/query/term.rs index 7f24147..9c772da 100644 --- a/ecs/src/query/term.rs +++ b/ecs/src/query/term.rs @@ -1,38 +1,115 @@ +use std::any::type_name; use std::marker::PhantomData; -use crate::component::Component; -use crate::query::{TermWithoutField, TermsBuilder, TermsBuilderInterface}; +use crate::component::{ + Component, + Handle as ComponentHandle, + HandleMut as ComponentHandleMut, +}; +use crate::query::{ + TermWithField, + TermWithoutField, + TermsBuilder, + TermsBuilderInterface, +}; +use crate::uid::With as WithUid; -pub struct With<ComponentT> +pub struct With<WithUidT> where - ComponentT: Component, + WithUidT: WithUid, { - _pd: PhantomData<ComponentT>, + _pd: PhantomData<WithUidT>, } -impl<ComponentT> TermWithoutField for With<ComponentT> +impl<WithUidT> TermWithoutField for With<WithUidT> where - ComponentT: Component, + WithUidT: WithUid, { - 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>(); + terms_builder.with::<WithUidT>(); } } -pub struct Without<ComponentT> +pub struct Without<WithUidT> where - ComponentT: Component, + WithUidT: WithUid, { - _pd: PhantomData<ComponentT>, + _pd: PhantomData<WithUidT>, } -impl<ComponentT> TermWithoutField for Without<ComponentT> +impl<WithUidT> TermWithoutField for Without<WithUidT> where - ComponentT: Component, + WithUidT: WithUid, { - 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>(); + terms_builder.without::<WithUidT>(); + } +} + +impl<ComponentT: Component> TermWithField for Option<&ComponentT> +{ + type Field<'a> = Option<ComponentHandle<'a, ComponentT>>; + + fn apply_to_terms_builder<const MAX_TERM_CNT: usize>( + _terms_builder: &mut TermsBuilder<MAX_TERM_CNT>, + ) + { + } + + fn get_field<'world>( + entity_handle: &crate::entity::Handle<'world>, + _world: &'world crate::World, + ) -> Self::Field<'world> + { + Some( + ComponentHandle::<'world, ComponentT>::from_entity_component_ref( + entity_handle + .get_matching_components(ComponentT::id()) + .next()?, + ) + .unwrap_or_else(|err| { + panic!( + "Creating handle to component {} failed: {err}", + type_name::<ComponentT>() + ); + }), + ) + } +} + +impl<ComponentT: Component> TermWithField for Option<&mut ComponentT> +{ + type Field<'a> = Option<ComponentHandleMut<'a, ComponentT>>; + + fn apply_to_terms_builder<const MAX_TERM_CNT: usize>( + _terms_builder: &mut TermsBuilder<MAX_TERM_CNT>, + ) + { + } + + fn get_field<'world>( + entity_handle: &crate::entity::Handle<'world>, + _world: &'world crate::World, + ) -> Self::Field<'world> + { + Some( + ComponentHandleMut::<'world, ComponentT>::from_entity_component_ref( + entity_handle + .get_matching_components(ComponentT::id()) + .next()?, + ) + .unwrap_or_else(|err| { + panic!( + "Creating handle to component {} failed: {err}", + type_name::<ComponentT>() + ); + }), + ) } } diff --git a/ecs/src/relationship.rs b/ecs/src/relationship.rs deleted file mode 100644 index 45fa265..0000000 --- a/ecs/src/relationship.rs +++ /dev/null @@ -1,466 +0,0 @@ -use std::any::type_name; -use std::marker::PhantomData; - -use ecs_macros::Component; - -use crate::component::storage::Storage as ComponentStorage; -use crate::component::{ - Component, - FromLockedOptional as FromLockedOptionalComponent, - Handle as ComponentHandle, - HandleMut as ComponentHandleMut, -}; -use crate::lock::{Error as LockError, Lock, ReadGuard}; -use crate::uid::{Kind as UidKind, Uid}; -use crate::World; - -/// A relationship to one or more targets. -#[derive(Debug, Component)] -#[component( - handle_type = Relation<'component, Kind, ComponentT>, - handle_mut_type = RelationMut<'component, Kind, ComponentT>, -)] -pub struct Relationship<Kind, ComponentT: Component> -where - Kind: 'static, -{ - entity_uid: SingleOrMultiple<Uid>, - _pd: PhantomData<(Kind, ComponentT)>, -} - -impl<Kind, ComponentT> Relationship<Kind, ComponentT> -where - ComponentT: Component, -{ - /// Creates a new `Relationship` with a single target. - #[must_use] - pub fn new(entity_uid: Uid) -> Self - { - debug_assert_eq!(entity_uid.kind(), UidKind::Entity); - - Self { - entity_uid: SingleOrMultiple::Single(entity_uid), - _pd: PhantomData, - } - } - - /// Creates a new `Relationship` with multiple targets. - #[must_use] - pub fn new_multiple(entity_uids: impl IntoIterator<Item = Uid>) -> Self - { - let uids = entity_uids.into_iter().collect::<Vec<_>>(); - - for euid in &uids { - debug_assert_eq!(euid.kind(), UidKind::Entity); - } - - Self { - entity_uid: SingleOrMultiple::Multiple(uids), - _pd: PhantomData, - } - } -} - -pub struct RelationMut<'rel_comp, Kind, ComponentT> -where - Kind: 'static, - ComponentT: Component, -{ - component_storage_lock: ReadGuard<'rel_comp, ComponentStorage>, - relationship_comp: ComponentHandleMut<'rel_comp, Relationship<Kind, ComponentT>>, -} - -impl<'rel_comp, Kind, ComponentT> FromLockedOptionalComponent<'rel_comp> - for RelationMut<'rel_comp, Kind, ComponentT> -where - ComponentT: Component, -{ - fn from_locked_optional_component( - optional_component: Option<&'rel_comp crate::lock::Lock<Box<dyn Component>>>, - world: &'rel_comp World, - ) -> Result<Self, LockError> - { - let relationship_comp_handle_from_locked_opt_comp = ComponentHandleMut::< - Relationship<Kind, ComponentT>, - >::from_locked_optional_component; - - let relationship_comp = - relationship_comp_handle_from_locked_opt_comp(optional_component, world)?; - - let component_storage_lock = world - .data - .component_storage - .read_nonblock() - .expect("Failed to aquire read-only component storage lock"); - - Ok(Self { - relationship_comp, - component_storage_lock, - }) - } -} - -impl<'rel_comp, Kind, ComponentT> FromLockedOptionalComponent<'rel_comp> - for Option<RelationMut<'rel_comp, Kind, ComponentT>> -where - ComponentT: Component, -{ - fn from_locked_optional_component( - optional_component: Option<&'rel_comp Lock<Box<dyn Component>>>, - world: &'rel_comp World, - ) -> Result<Self, crate::lock::Error> - { - optional_component - .map(|component| { - RelationMut::from_locked_optional_component(Some(component), world) - }) - .transpose() - } -} - -impl<'rel_comp, Kind, ComponentT> RelationMut<'rel_comp, Kind, ComponentT> -where - ComponentT: Component, -{ - /// Returns the component of the target at the specified index. - /// - /// # Panics - /// Will panic if the entity does not exist in the archetype it belongs to. This - /// should hopefully never happend. - #[must_use] - pub fn get(&self, index: usize) -> Option<ComponentHandleMut<'_, ComponentT>> - { - let target = self.get_target(index)?; - - let archetype = self.component_storage_lock.get_entity_archetype(*target)?; - - let entity = archetype - .get_entity_by_id(*target) - .expect("Target entity is gone from archetype"); - - let component_index = archetype.get_index_for_component(ComponentT::id())?; - - let component = ComponentHandleMut::new( - entity - .components() - .get(component_index)? - .component() - .write_nonblock() - .unwrap_or_else(|_| { - panic!( - "Failed to aquire read-write lock of component {}", - type_name::<ComponentT>() - ) - }), - ); - - Some(component) - } - - /// Returns a reference to the target at the specified index. - #[must_use] - pub fn get_target(&self, index: usize) -> Option<&Uid> - { - match &self.relationship_comp.entity_uid { - SingleOrMultiple::Single(entity_uid) if index == 0 => Some(entity_uid), - SingleOrMultiple::Multiple(entity_uids) => entity_uids.get(index), - SingleOrMultiple::Single(_) => None, - } - } - - /// Returns a mutable reference to the target at the specified index. - #[must_use] - pub fn get_target_mut(&mut self, index: usize) -> Option<&mut Uid> - { - match &mut self.relationship_comp.entity_uid { - SingleOrMultiple::Single(entity_uid) if index == 0 => Some(entity_uid), - SingleOrMultiple::Multiple(entity_uids) => entity_uids.get_mut(index), - SingleOrMultiple::Single(_) => None, - } - } - - /// Adds a target to the relationship. - pub fn add_target(&mut self, entity_uid: Uid) - { - debug_assert_eq!(entity_uid.kind(), UidKind::Entity); - - match &mut self.relationship_comp.entity_uid { - SingleOrMultiple::Single(prev_entity_uid) => { - self.relationship_comp.entity_uid = - SingleOrMultiple::Multiple(vec![*prev_entity_uid, entity_uid]); - } - SingleOrMultiple::Multiple(entity_uids) => entity_uids.push(entity_uid), - } - } - - /// Removes a target to the relationship, returning it. - pub fn remove_target(&mut self, index: usize) -> Option<Uid> - { - match &mut self.relationship_comp.entity_uid { - SingleOrMultiple::Single(entity_uid) => { - let prev_entity_uid = *entity_uid; - - self.relationship_comp.entity_uid = - SingleOrMultiple::Multiple(Vec::new()); - - Some(prev_entity_uid) - } - SingleOrMultiple::Multiple(entity_uids) => { - if index >= entity_uids.len() { - return None; - } - - Some(entity_uids.remove(index)) - } - } - } - - #[must_use] - pub fn target_count(&self) -> usize - { - match &self.relationship_comp.entity_uid { - SingleOrMultiple::Single(_) => 1, - SingleOrMultiple::Multiple(entity_uids) => entity_uids.len(), - } - } - - /// Returns a iterator of the components of the targets of this relationship. - #[must_use] - pub fn iter(&self) -> TargetComponentIterMut<'_, 'rel_comp, Kind, ComponentT> - { - TargetComponentIterMut { relation: self, index: 0 } - } -} - -impl<'relationship, 'rel_comp, Kind, ComponentT> IntoIterator - for &'relationship RelationMut<'rel_comp, Kind, ComponentT> -where - 'relationship: 'rel_comp, - ComponentT: Component, -{ - type IntoIter = TargetComponentIterMut<'relationship, 'rel_comp, Kind, ComponentT>; - type Item = ComponentHandleMut<'rel_comp, ComponentT>; - - fn into_iter(self) -> Self::IntoIter - { - self.iter() - } -} - -/// Iterator of the components of the targets of a relationship. -pub struct TargetComponentIterMut<'relationship, 'rel_comp, Kind, ComponentT> -where - Kind: 'static, - ComponentT: Component, -{ - relation: &'relationship RelationMut<'rel_comp, Kind, ComponentT>, - index: usize, -} - -impl<'relationship, 'rel_comp, Kind, ComponentT> Iterator - for TargetComponentIterMut<'relationship, 'rel_comp, Kind, ComponentT> -where - 'relationship: 'rel_comp, - Kind: 'static, - ComponentT: Component, -{ - type Item = ComponentHandleMut<'rel_comp, ComponentT>; - - fn next(&mut self) -> Option<Self::Item> - { - let index = self.index; - - self.index += 1; - - self.relation.get(index) - } -} - -#[derive(Debug)] -enum SingleOrMultiple<Value> -{ - Single(Value), - Multiple(Vec<Value>), -} - -pub struct Relation<'rel_comp, Kind, ComponentT> -where - Kind: 'static, - ComponentT: Component, -{ - component_storage_lock: ReadGuard<'rel_comp, ComponentStorage>, - relationship_comp: ComponentHandle<'rel_comp, Relationship<Kind, ComponentT>>, -} - -impl<'rel_comp, Kind, ComponentT> FromLockedOptionalComponent<'rel_comp> - for Relation<'rel_comp, Kind, ComponentT> -where - ComponentT: Component, -{ - fn from_locked_optional_component( - optional_component: Option<&'rel_comp Lock<Box<dyn Component>>>, - world: &'rel_comp World, - ) -> Result<Self, LockError> - { - let relationship_comp_handle_from_locked_opt_comp = ComponentHandle::< - Relationship<Kind, ComponentT>, - >::from_locked_optional_component; - - let relationship_comp = - relationship_comp_handle_from_locked_opt_comp(optional_component, world)?; - - let component_storage_lock = world - .data - .component_storage - .read_nonblock() - .expect("Failed to aquire read-only component storage lock"); - - Ok(Self { - relationship_comp, - component_storage_lock, - }) - } -} - -impl<'rel_comp, Kind, ComponentT> FromLockedOptionalComponent<'rel_comp> - for Option<Relation<'rel_comp, Kind, ComponentT>> -where - ComponentT: Component, -{ - fn from_locked_optional_component( - optional_component: Option<&'rel_comp Lock<Box<dyn Component>>>, - world: &'rel_comp World, - ) -> Result<Self, crate::lock::Error> - { - optional_component - .map(|component| { - Relation::from_locked_optional_component(Some(component), world) - }) - .transpose() - } -} - -impl<'rel_comp, Kind, ComponentT> Relation<'rel_comp, Kind, ComponentT> -where - ComponentT: Component, -{ - /// Returns the component of the target at the specified index. - /// - /// # Panics - /// Will panic if the entity does not exist in the archetype it belongs to. This - /// should hopefully never happend. - #[must_use] - pub fn get(&self, index: usize) -> Option<ComponentHandle<'_, ComponentT>> - { - let target = self.get_target(index)?; - - let archetype = self.component_storage_lock.get_entity_archetype(*target)?; - - let entity = archetype - .get_entity_by_id(*target) - .expect("Target entity is gone from archetype"); - - let component_index = archetype.get_index_for_component(ComponentT::id())?; - - let component = ComponentHandle::new( - entity - .components() - .get(component_index)? - .component() - .read_nonblock() - .unwrap_or_else(|_| { - panic!( - "Failed to aquire read-write lock of component {}", - type_name::<ComponentT>() - ) - }), - ); - - Some(component) - } - - /// Returns a reference to the target at the specified index. - #[must_use] - pub fn get_target(&self, index: usize) -> Option<&Uid> - { - match &self.relationship_comp.entity_uid { - SingleOrMultiple::Single(entity_uid) if index == 0 => Some(entity_uid), - SingleOrMultiple::Multiple(entity_uids) => entity_uids.get(index), - SingleOrMultiple::Single(_) => None, - } - } - - #[must_use] - pub fn target_count(&self) -> usize - { - match &self.relationship_comp.entity_uid { - SingleOrMultiple::Single(_) => 1, - SingleOrMultiple::Multiple(entity_uids) => entity_uids.len(), - } - } - - pub fn target_uids(&self) -> impl Iterator<Item = Uid> + '_ - { - (0..self.target_count()) - .map_while(|target_index| self.get_target(target_index).copied()) - } - - /// Returns a iterator of the components of the targets of this relationship. - #[must_use] - pub fn iter(&self) -> TargetComponentIter<'_, 'rel_comp, Kind, ComponentT> - { - TargetComponentIter { relation: self, index: 0 } - } -} - -impl<'relationship, 'rel_comp, Kind, ComponentT> IntoIterator - for &'relationship Relation<'rel_comp, Kind, ComponentT> -where - 'relationship: 'rel_comp, - ComponentT: Component, -{ - type IntoIter = TargetComponentIter<'relationship, 'rel_comp, Kind, ComponentT>; - type Item = ComponentHandle<'rel_comp, ComponentT>; - - fn into_iter(self) -> Self::IntoIter - { - self.iter() - } -} - -/// Iterator of the components of the targets of a relationship. -pub struct TargetComponentIter<'relationship, 'rel_comp, Kind, ComponentT> -where - Kind: 'static, - ComponentT: Component, -{ - relation: &'relationship Relation<'rel_comp, Kind, ComponentT>, - index: usize, -} - -impl<'relationship, 'rel_comp, Kind, ComponentT> Iterator - for TargetComponentIter<'relationship, 'rel_comp, Kind, ComponentT> -where - 'relationship: 'rel_comp, - Kind: 'static, - ComponentT: Component, -{ - type Item = ComponentHandle<'rel_comp, ComponentT>; - - fn next(&mut self) -> Option<Self::Item> - { - let index = self.index; - - self.index += 1; - - self.relation.get(index) - } -} - -/// Relationship kind denoting a dependency to another entity -#[derive(Debug, Default, Clone, Copy)] -pub struct DependsOn; - -/// Relationship kind denoting being the child of another entity. -#[derive(Debug, Default, Clone, Copy)] -pub struct ChildOf; diff --git a/ecs/src/sole.rs b/ecs/src/sole.rs index 5af5ce3..1cce419 100644 --- a/ecs/src/sole.rs +++ b/ecs/src/sole.rs @@ -6,11 +6,10 @@ use std::sync::{Arc, Weak}; use crate::lock::{Lock, WriteGuard}; use crate::system::{Param as SystemParam, System}; -use crate::type_name::TypeName; use crate::World; /// A type which has a single instance and is shared globally. -pub trait Sole: Any + TypeName +pub trait Sole: Any { fn drop_last(&self) -> bool; @@ -40,14 +39,6 @@ impl Debug for dyn Sole } } -impl TypeName for Box<dyn Sole> -{ - fn type_name(&self) -> &'static str - { - self.as_ref().type_name() - } -} - /// Holds a reference to a globally shared singleton value. #[derive(Debug)] pub struct Single<'world, SoleT: Sole> diff --git a/ecs/src/system/stateful.rs b/ecs/src/system/stateful.rs index 9d911ee..54f6979 100644 --- a/ecs/src/system/stateful.rs +++ b/ecs/src/system/stateful.rs @@ -1,4 +1,4 @@ -use std::any::{Any, TypeId}; +use std::any::{type_name, Any, TypeId}; use std::panic::{RefUnwindSafe, UnwindSafe}; use hashbrown::HashMap; @@ -25,7 +25,7 @@ use crate::World; pub struct Stateful<Func> { func: Func, - local_components: HashMap<Uid, Lock<Box<dyn Component>>>, + local_components: HashMap<Uid, Lock<Box<dyn Any>>>, } macro_rules! impl_system { @@ -127,7 +127,10 @@ macro_rules! impl_system { self.local_components .insert( LocalComponent::id(), - Lock::new(Box::new(local_component)) + Lock::new( + Box::new(local_component), + type_name::<LocalComponent>() + ) ); } } diff --git a/ecs/src/type_name.rs b/ecs/src/type_name.rs deleted file mode 100644 index 54179be..0000000 --- a/ecs/src/type_name.rs +++ /dev/null @@ -1,15 +0,0 @@ -use std::any::type_name; - -pub trait TypeName -{ - /// Returns the name of this type. - fn type_name(&self) -> &'static str; -} - -impl<Item> TypeName for Vec<Item> -{ - fn type_name(&self) -> &'static str - { - type_name::<Self>() - } -} diff --git a/ecs/src/uid.rs b/ecs/src/uid.rs index c3ed85b..feed62c 100644 --- a/ecs/src/uid.rs +++ b/ecs/src/uid.rs @@ -1,23 +1,28 @@ -use std::fmt::{Debug, Formatter}; +use std::fmt::{Debug, Display, Formatter}; use std::mem::transmute; use std::sync::atomic::{AtomicU32, Ordering}; +use crate::component::Component; use crate::util::{gen_mask_64, BitMask, NumberExt}; -static NEXT: AtomicU32 = AtomicU32::new(1); +static NEXT: AtomicU32 = AtomicU32::new(Uid::FIRST_UNIQUE_ID); + +static WILDCARD_ID: u32 = 1; const ID_BITS: BitMask<u64> = BitMask::new(gen_mask_64!(32..=63)); +const RELATION_BITS: BitMask<u64> = BitMask::new(gen_mask_64!(6..=31)); const KIND_BITS: BitMask<u64> = BitMask::new(gen_mask_64!(0..=1)); #[derive(Debug, Clone, Copy, Hash, PartialEq, Eq, PartialOrd, Ord)] #[repr(u8)] pub enum Kind { + Pair = 3, Entity = 2, Component = 1, } -/// Unique entity/component ID. +/// A unique identifier. #[derive(Clone, Copy, Hash, PartialEq, Eq, PartialOrd, Ord)] pub struct Uid { @@ -26,6 +31,10 @@ pub struct Uid impl Uid { + /// The id part of the first unique `Uid`. The ids `0..Uid::FIRST_UNIQUE_ID` are + /// reserved. + pub const FIRST_UNIQUE_ID: u32 = 5; + /// Returns a new unique entity/component ID. pub fn new_unique(kind: Kind) -> Self { @@ -37,6 +46,41 @@ impl Uid } #[must_use] + pub fn wildcard() -> Self + { + Self { + inner: ID_BITS.field_prep(u64::from(WILDCARD_ID)) + | KIND_BITS.field_prep(Kind::Component as u64), + } + } + + /// Returns a new pair UID. + /// + /// # Panics + /// Will panic if either the given relation or target is a pair UID. + #[must_use] + pub fn new_pair(params: &PairParams) -> Self + { + assert_ne!( + params.relation.kind(), + Kind::Pair, + "Pair relation cannot be a pair" + ); + + assert_ne!( + params.target.kind(), + Kind::Pair, + "Pair target cannot be a pair" + ); + + Self { + inner: ID_BITS.field_prep(u64::from(params.target.id())) + | RELATION_BITS.field_prep(u64::from(params.relation.id())) + | KIND_BITS.field_prep(Kind::Pair as u64), + } + } + + #[must_use] pub fn id(&self) -> u32 { let Ok(id) = u32::try_from(self.inner.field_get(ID_BITS)) else { @@ -57,6 +101,81 @@ impl Uid // in the new_unique function unsafe { transmute::<u8, Kind>(kind) } } + + /// If this `Uid` is a pair, returns the relation as a component `Uid`. + /// + /// # Panics + /// Will panic if this `Uid` is not a pair. + #[must_use] + pub fn relation_component(&self) -> Self + { + assert_eq!(self.kind(), Kind::Pair, "Uid is not a pair"); + + Self { + inner: ID_BITS.field_prep(u64::from(self.relation())) + | KIND_BITS.field_prep(Kind::Component as u64), + } + } + + #[must_use] + pub fn has_same_relation_as(&self, other: Self) -> bool + { + self.relation() == other.relation() + } + + /// If this `Uid` is a pair, returns the relation as a entity `Uid`. + /// + /// # Panics + /// Will panic if this `Uid` is not a pair. + #[must_use] + pub fn relation_entity(&self) -> Self + { + assert_eq!(self.kind(), Kind::Pair, "Uid is not a pair"); + + Self { + inner: ID_BITS.field_prep(u64::from(self.relation())) + | KIND_BITS.field_prep(Kind::Entity as u64), + } + } + + /// If this `Uid` is a pair, returns the target as a component `Uid`. + /// + /// # Panics + /// Will panic if this `Uid` is not a pair. + #[must_use] + pub fn target_component(&self) -> Self + { + assert_eq!(self.kind(), Kind::Pair, "Uid is not a pair"); + + Self { + inner: ID_BITS.field_prep(u64::from(self.id())) + | KIND_BITS.field_prep(Kind::Component as u64), + } + } + + /// If this `Uid` is a pair, returns the target as a entity `Uid`. + /// + /// # Panics + /// Will panic if this `Uid` is not a pair. + #[must_use] + pub fn target_entity(&self) -> Self + { + assert_eq!(self.kind(), Kind::Pair, "Uid is not a pair"); + + Self { + inner: ID_BITS.field_prep(u64::from(self.id())) + | KIND_BITS.field_prep(Kind::Entity as u64), + } + } + + fn relation(self) -> u32 + { + let Ok(relation) = u32::try_from(self.inner.field_get(RELATION_BITS)) else { + unreachable!("Uid relation does not fit in u32"); + }; + + relation + } } impl Debug for Uid @@ -70,3 +189,55 @@ impl Debug for Uid .finish_non_exhaustive() } } + +impl Display for Uid +{ + fn fmt(&self, formatter: &mut Formatter<'_>) -> std::fmt::Result + { + if self.kind() == Kind::Pair { + return write!( + formatter, + "({}, {})", + self.relation(), + self.target_component() + ); + } + + if *self == Uid::wildcard() { + return write!(formatter, "*"); + } + + write!(formatter, "{}", self.id()) + } +} + +#[derive(Debug, Clone)] +pub struct PairParams +{ + pub relation: Uid, + pub target: Uid, +} + +pub trait With: 'static +{ + fn uid() -> Uid; +} + +impl<ComponentT: Component> With for ComponentT +{ + fn uid() -> Uid + { + Self::id() + } +} + +#[derive(Debug)] +pub enum Wildcard {} + +impl With for Wildcard +{ + fn uid() -> Uid + { + Uid::wildcard() + } +} diff --git a/ecs/src/util.rs b/ecs/src/util.rs index 6f7aed7..9ab4dc6 100644 --- a/ecs/src/util.rs +++ b/ecs/src/util.rs @@ -4,6 +4,8 @@ use std::ops::{BitAnd, Deref}; use hashbrown::HashMap; +pub(crate) 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..a37b1f9 --- /dev/null +++ b/ecs/src/util/array_vec.rs @@ -0,0 +1,131 @@ +use std::mem::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> +{ + #[inline] + #[must_use] + pub fn len(&self) -> usize + { + self.len + } + + #[inline] + #[must_use] + pub fn is_empty(&self) -> bool + { + self.len == 0 + } + + 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] + { + let ptr = &raw const self.items[..self.len]; + + unsafe { &*(ptr as *const [Item]) } + } +} + +impl<Item, const CAPACITY: usize> AsMut<[Item]> for ArrayVec<Item, CAPACITY> +{ + fn as_mut(&mut self) -> &mut [Item] + { + let ptr = &raw mut self.items[..self.len]; + + unsafe { &mut *(ptr as *mut [Item]) } + } +} + +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, + } + } +} + +impl<Item, const CAPACITY: usize> Drop for ArrayVec<Item, CAPACITY> +{ + fn drop(&mut self) + { + for item in &mut self.items[..self.len] { + // SAFETY: The items from index 0 to the length index will always be + // initialized and satisfy all the invariants of the Item type. + unsafe { + item.assume_init_drop(); + } + } + } +} |