summaryrefslogtreecommitdiff
path: root/ecs/src/component.rs
diff options
context:
space:
mode:
Diffstat (limited to 'ecs/src/component.rs')
-rw-r--r--ecs/src/component.rs497
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(),
+ }
}
}