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.rs496
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(),
+ }
}
}