diff options
Diffstat (limited to 'ecs/src/component.rs')
-rw-r--r-- | ecs/src/component.rs | 497 |
1 files changed, 214 insertions, 283 deletions
diff --git a/ecs/src/component.rs b/ecs/src/component.rs index 35e5430..5a8cd0b 100644 --- a/ecs/src/component.rs +++ b/ecs/src/component.rs @@ -1,88 +1,53 @@ 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, + MappedReadGuard, + MappedWriteGuard, + ReadGuard, + WriteGuard, }; -use crate::lock::{Error as LockError, Lock, ReadGuard, WriteGuard}; -use crate::system::{ComponentRef, ComponentRefMut, Input as SystemInput}; -use crate::type_name::TypeName; +use crate::system::Input as SystemInput; use crate::uid::Uid; use crate::util::Array; -use crate::{EntityComponent, 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 RefMut<'component>: FromOptionalMut<'component> + FromLockedOptional<'component> - where - Self: Sized; - - type Ref<'component>: FromOptional<'component> + FromLockedOptional<'component> - where - Self: Sized; - /// Returns the ID of this component. fn id() -> Uid where Self: Sized; - /// The ID of the component `self`. Returns the same value as [`Component::id`]. - fn self_id(&self) -> Uid; - - /// Returns the component UID of a component event for this component. - fn get_event_uid(&self, event_kind: ComponentEventKind) -> Uid; - - #[doc(hidden)] - fn as_any_mut(&mut self) -> &mut dyn Any; - - #[doc(hidden)] - fn as_any(&self) -> &dyn Any; - - /// Whether the component `self` is optional. Returns the same value as - /// [`Component::is_optional`]. - fn self_is_optional(&self) -> IsOptional - { - IsOptional::No - } - - /// Returns whether this component is optional. - #[must_use] - fn is_optional() -> IsOptional - where - Self: Sized, - { - IsOptional::No - } + /// Returns the name of this component. + fn name(&self) -> &'static str; } impl dyn Component { pub fn downcast_mut<Real: 'static>(&mut self) -> Option<&mut Real> { - self.as_any_mut().downcast_mut() + (self as &mut dyn Any).downcast_mut() } pub fn downcast_ref<Real: 'static>(&self) -> Option<&Real> { - self.as_any().downcast_ref() + (self as &dyn Any).downcast_ref() } pub fn is<Other: 'static>(&self) -> bool { - self.as_any().is::<Other>() + (self as &dyn Any).is::<Other>() } } @@ -94,326 +59,292 @@ impl Debug for dyn Component } } -impl TypeName for Box<dyn Component> +/// A sequence of components. +pub trait Sequence { - fn type_name(&self) -> &'static str - { - self.as_ref().type_name() - } + /// The number of components in this component sequence. + const COUNT: usize; + + type PartsArray: Array<Parts>; + + fn into_parts_array(self) -> Self::PartsArray; } -impl<ComponentT> Component for Option<ComponentT> -where - ComponentT: Component, +#[derive(Debug)] +pub struct Handle<'a, ComponentData: 'static> { - type Component = ComponentT; - type Ref<'component> = Option<ComponentRef<'component, ComponentT>>; - type RefMut<'component> = Option<ComponentRefMut<'component, ComponentT>>; - - fn id() -> Uid - { - ComponentT::id() - } + inner: MappedReadGuard<'a, ComponentData>, +} - fn self_id(&self) -> Uid +impl<'comp, ComponentData: 'static> Handle<'comp, ComponentData> +{ + /// 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> { - Self::id() + Ok(Self::new( + entity_component_ref + .component() + .read_nonblock() + .map_err(AcquireLockError)?, + )) } - fn get_event_uid(&self, event_kind: ComponentEventKind) -> Uid + pub(crate) fn new(inner: ReadGuard<'comp, Box<dyn Any>>) -> Self { - match event_kind { - ComponentEventKind::Removed => ComponentRemovedEvent::<Self>::id(), + Self { + inner: inner.map(|component| { + component + .downcast_ref::<ComponentData>() + .unwrap_or_else(|| { + panic!( + "Failed to downcast component to type {}", + type_name::<ComponentData>() + ); + }) + }), } } +} - fn as_any_mut(&mut self) -> &mut dyn Any +impl<ComponentData: 'static> Deref for Handle<'_, ComponentData> +{ + type Target = ComponentData; + + fn deref(&self) -> &Self::Target { - self + &self.inner } +} - fn as_any(&self) -> &dyn Any +#[derive(Debug)] +pub struct HandleMut<'a, ComponentData: 'static> +{ + inner: MappedWriteGuard<'a, ComponentData>, +} + +impl<'comp, ComponentData: 'static> HandleMut<'comp, ComponentData> +{ + /// 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> { - self + Ok(Self::new( + entity_component_ref + .component() + .write_nonblock() + .map_err(AcquireLockError)?, + )) } - fn self_is_optional(&self) -> IsOptional + pub(crate) fn new(inner: WriteGuard<'comp, Box<dyn Any>>) -> Self { - Self::is_optional() + Self { + inner: inner.map(|component| { + component + .downcast_mut::<ComponentData>() + .unwrap_or_else(|| { + panic!( + "Failed to downcast component to type {}", + type_name::<ComponentData>() + ); + }) + }), + } } +} + +impl<ComponentData: 'static> Deref for HandleMut<'_, ComponentData> +{ + type Target = ComponentData; - fn is_optional() -> IsOptional + fn deref(&self) -> &Self::Target { - IsOptional::Yes + &self.inner } } -impl<ComponentT> TypeName for Option<ComponentT> -where - ComponentT: Component, +impl<ComponentData: 'static> DerefMut for HandleMut<'_, ComponentData> { - fn type_name(&self) -> &'static str + fn deref_mut(&mut self) -> &mut Self::Target { - type_name::<Self>() + &mut self.inner } } -impl<ComponentT> SystemInput for Option<ComponentT> where ComponentT: Component {} - -/// A sequence of components. -pub trait Sequence +#[derive(Debug, thiserror::Error)] +pub enum HandleError { - /// The number of components in this component sequence. - const COUNT: usize; + #[error(transparent)] + AcquireLockFailed(#[from] AcquireLockError), +} - fn into_vec(self) -> Vec<Box<dyn Component>>; +#[derive(Debug, thiserror::Error)] +#[error("Failed to acquire component lock")] +pub struct AcquireLockError(#[source] LockError); - fn metadata() -> impl Array<Metadata>; +macro_rules! inner { + ($c: tt) => { + seq!(I in 0..=$c { + impl<#(IntoCompParts~I: IntoParts,)*> Sequence for (#(IntoCompParts~I,)*) + { + const COUNT: usize = $c + 1; - fn added_event_ids() -> Vec<Uid>; + type PartsArray = [Parts; $c + 1]; - fn removed_event_ids() -> Vec<Uid>; + fn into_parts_array(self) -> Self::PartsArray + { + [#({ + self.I.into_parts() + },)*] + } + } + }); + }; } -/// A sequence of references (immutable or mutable) to components. -pub trait RefSequence -{ - type Handles<'component>; - - type Metadata: Array<Metadata>; +seq!(C in 0..=16 { + inner!(C); +}); - fn metadata() -> Self::Metadata; +impl Sequence for () +{ + type PartsArray = [Parts; 0]; - fn from_components<'component>( - components: &'component [EntityComponent], - component_index_lookup: impl Fn(Uid) -> Option<usize>, - world: &'component World, - ) -> Self::Handles<'component>; -} + const COUNT: usize = 0; -/// A mutable or immutable reference to a component. -pub trait Ref -{ - type Component: Component; - type Handle<'component>: FromLockedOptional<'component>; + fn into_parts_array(self) -> Self::PartsArray + { + [] + } } -impl<ComponentT> Ref for &ComponentT -where - ComponentT: Component, +pub trait IntoParts { - type Component = ComponentT; - type Handle<'component> = ComponentT::Ref<'component>; + fn into_parts(self) -> Parts; } -impl<ComponentT> Ref for &mut ComponentT +impl<ComponentT> IntoParts for ComponentT where ComponentT: Component, { - type Component = ComponentT; - type Handle<'component> = ComponentT::RefMut<'component>; + fn into_parts(self) -> Parts + { + Parts::builder() + .name(type_name::<Self>()) + .build(Self::id(), self) + } } -/// [`Component`] metadata. -#[derive(Debug, Clone)] +/// The parts of a component. +#[derive(Debug)] #[non_exhaustive] -pub struct Metadata +pub struct Parts { - pub id: Uid, - pub is_optional: IsOptional, + id: Uid, + name: &'static str, + data: Box<dyn Any>, } -impl Metadata +impl Parts { - pub fn get<ComponentT: Component + ?Sized>(component: &ComponentT) -> Self + #[must_use] + pub fn id(&self) -> Uid { - Self { - id: component.self_id(), - is_optional: component.self_is_optional(), - } + self.id } - pub fn of<ComponentT: Component>() -> Self + #[must_use] + pub fn name(&self) -> &'static str { - Self { - id: ComponentT::id(), - is_optional: ComponentT::is_optional(), - } + self.name } -} - -/// Whether or not a `Component` is optional. -#[derive(Debug, Clone, Copy, PartialEq, Eq)] -pub enum IsOptional -{ - Yes, - No, -} -impl From<bool> for IsOptional -{ - fn from(is_optional: bool) -> Self + #[must_use] + pub fn builder() -> PartsBuilder { - if is_optional { - return IsOptional::Yes; - } + PartsBuilder::default() + } - IsOptional::No + pub(crate) fn into_data(self) -> Box<dyn Any> + { + self.data } } -pub trait FromOptionalMut<'comp> +#[derive(Debug)] +pub struct PartsBuilder { - fn from_optional_mut_component( - optional_component: Option<WriteGuard<'comp, Box<dyn Component>>>, - world: &'comp World, - ) -> Self; + name: &'static str, } -pub trait FromOptional<'comp> +impl PartsBuilder { - fn from_optional_component( - optional_component: Option<ReadGuard<'comp, Box<dyn Component>>>, - world: &'comp World, - ) -> Self; + #[must_use] + pub fn name(mut self, name: &'static str) -> Self + { + self.name = name; + self + } + + #[must_use] + pub fn build<Data: 'static>(self, id: Uid, data: Data) -> Parts + { + Parts { + id, + name: self.name, + data: Box::new(data), + } + } } -pub trait FromLockedOptional<'comp>: Sized +impl Default for PartsBuilder { - fn from_locked_optional_component( - optional_component: Option<&'comp Lock<Box<dyn Component>>>, - world: &'comp World, - ) -> Result<Self, LockError>; + fn default() -> Self + { + Self { name: "(unspecified)" } + } } -macro_rules! inner { - ($c: tt) => { - seq!(I in 0..=$c { - impl<#(Comp~I: Component,)*> Sequence for (#(Comp~I,)*) - where - #(for<'comp> Comp~I::RefMut<'comp>: FromOptionalMut<'comp>,)* - #(for<'comp> Comp~I::Ref<'comp>: FromOptional<'comp>,)* - { - const COUNT: usize = $c + 1; - - fn into_vec(self) -> Vec<Box<dyn Component>> - { - Vec::from_iter([#(Box::new(self.I) as Box<dyn Component>,)*]) - } - - fn metadata() -> impl Array<Metadata> - { - [ - #( - Metadata { - id: Comp~I::id(), - is_optional: Comp~I::is_optional(), - }, - )* - ] - } - - fn added_event_ids() -> Vec<Uid> - { - vec![ - #(ComponentAddedEvent::<Comp~I>::id(),)* - ] - } - - fn removed_event_ids() -> Vec<Uid> - { - vec![ - #(ComponentRemovedEvent::<Comp~I>::id(),)* - ] - } - } - - impl<#(CompRef~I: Ref,)*> RefSequence for (#(CompRef~I,)*) - { - type Handles<'component> = (#(CompRef~I::Handle<'component>,)*); - - type Metadata = [Metadata; $c + 1]; - - fn metadata() -> Self::Metadata - { - [#( - Metadata { - id: CompRef~I::Component::id(), - is_optional: CompRef~I::Component::is_optional(), - }, - )*] - } - - fn from_components<'component>( - components: &'component [EntityComponent], - component_index_lookup: impl Fn(Uid) -> Option<usize>, - world: &'component World, - ) -> Self::Handles<'component> - { - (#( - CompRef~I::Handle::from_locked_optional_component( - component_index_lookup(CompRef~I::Component::id()) - .and_then(|component_index| components.get(component_index)) - .map(|component| &component.component), - world, - ).unwrap_or_else(|err| { - panic!( - "Taking component {} lock failed: {err}", - type_name::<CompRef~I::Component>() - ); - }), - )*) - } - } - }); - }; +/// Pending component removals for a entity. +#[derive(Debug, Clone, Component)] +pub struct Removals +{ + component_ids: HashSet<Uid>, } -seq!(C in 0..=16 { - inner!(C); -}); - -impl Sequence for () +impl Removals { - const COUNT: usize = 0; - - fn into_vec(self) -> Vec<Box<dyn Component>> - { - Vec::new() - } - - fn metadata() -> impl Array<Metadata> + pub fn contains<ComponentT: Component>(&self) -> bool { - [] + self.contains_id(ComponentT::id()) } - fn added_event_ids() -> Vec<Uid> + pub fn contains_id(&self, component_id: Uid) -> bool { - Vec::new() + self.component_ids.contains(&component_id) } - fn removed_event_ids() -> Vec<Uid> + pub(crate) fn add_ids(&mut self, ids: impl IntoIterator<Item = Uid>) { - Vec::new() + self.component_ids.extend(ids) } } -impl RefSequence for () +impl FromIterator<Uid> for Removals { - type Handles<'component> = (); - type Metadata = [Metadata; 0]; - - fn metadata() -> Self::Metadata - { - [] - } - - fn from_components<'component>( - _components: &'component [EntityComponent], - _component_index_lookup: impl Fn(Uid) -> Option<usize>, - _world: &'component World, - ) -> Self::Handles<'component> + fn from_iter<T: IntoIterator<Item = Uid>>(iter: T) -> Self { - () + Self { + component_ids: iter.into_iter().collect(), + } } } |