diff options
Diffstat (limited to 'ecs/src/component.rs')
-rw-r--r-- | ecs/src/component.rs | 496 |
1 files changed, 187 insertions, 309 deletions
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(), + } } } |