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.rs475
1 files changed, 162 insertions, 313 deletions
diff --git a/ecs/src/component.rs b/ecs/src/component.rs
index 525bd98..e4ecfce 100644
--- a/ecs/src/component.rs
+++ b/ecs/src/component.rs
@@ -4,66 +4,34 @@ use std::ops::{Deref, DerefMut};
use seq_macro::seq;
-use crate::event::component::{
- Added as ComponentAddedEvent,
- Kind as ComponentEventKind,
- Removed as ComponentRemovedEvent,
-};
+use crate::event::component::Changed;
+use crate::event::Submitter as EventSubmitter;
use crate::lock::{
Error as LockError,
- Lock,
MappedReadGuard,
MappedWriteGuard,
ReadGuard,
WriteGuard,
};
+use crate::pair::Pair;
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, World};
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 +60,55 @@ 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>;
-}
+ type PartsArray: Array<Parts>;
-/// 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,
-{
- 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>;
-}
-
-/// [`Component`] metadata.
-#[derive(Debug, Clone)]
-#[non_exhaustive]
-pub struct Metadata
+#[derive(Debug)]
+pub struct Handle<'a, DataT: 'static>
{
- pub id: Uid,
- pub is_optional: bool,
+ inner: MappedReadGuard<'a, DataT>,
}
-impl Metadata
+impl<'comp, DataT: 'static> Handle<'comp, DataT>
{
- #[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(),
- }
- }
-}
-
-pub trait FromLockedOptional<'comp>: Sized
-{
- /// 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>,
-}
-
-impl<'a, ComponentT: Component> Handle<'a, ComponentT>
-{
- pub(crate) fn new(inner: ReadGuard<'a, Box<dyn Component>>) -> Self
+ /// 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 {
- inner: inner.map(|component| {
- component.downcast_ref::<ComponentT>().unwrap_or_else(|| {
- panic!(
- "Cannot downcast component {} to type {}",
- component.type_name(),
- type_name::<ComponentT>()
- );
- })
- }),
- }
+ Self::new(
+ entity_component_ref
+ .component()
+ .read_nonblock()
+ .map_err(AcquireLockError)?,
+ )
}
-}
-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>
+ fn new(inner: ReadGuard<'comp, Box<dyn Any>>) -> Result<Self, HandleError>
{
- optional_component
- .map(|lock| Ok(Handle::new(lock.read_nonblock()?)))
- .transpose()
+ Ok(Self {
+ inner: ReadGuard::try_map(inner, |component| {
+ component.downcast_ref::<DataT>()
+ })
+ .map_err(|_| HandleError::IncorrectType)?,
+ })
}
}
-impl<ComponentT: Component> Deref for Handle<'_, ComponentT>
+impl<DataT: 'static> Deref for Handle<'_, DataT>
{
- type Target = ComponentT;
+ type Target = DataT;
fn deref(&self) -> &Self::Target
{
@@ -293,67 +117,51 @@ impl<ComponentT: Component> Deref for Handle<'_, ComponentT>
}
#[derive(Debug)]
-pub struct HandleMut<'a, ComponentT: Component>
+pub struct HandleMut<'a, DataT: 'static>
{
- inner: MappedWriteGuard<'a, ComponentT>,
+ entity_component_ref: EntityComponentRef<'a>,
+ inner: MappedWriteGuard<'a, DataT>,
+ event_submitter: EventSubmitter<'a>,
}
-impl<'a, ComponentT: Component> HandleMut<'a, ComponentT>
+impl<'comp, DataT: 'static> HandleMut<'comp, DataT>
{
- 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>,
+ world: &'comp World,
+ ) -> Result<Self, HandleError>
{
- 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>()
- );
- })
- }),
- }
+ let inner = entity_component_ref
+ .component()
+ .write_nonblock()
+ .map_err(AcquireLockError)?;
+
+ Ok(Self {
+ entity_component_ref: entity_component_ref.clone(),
+ inner: WriteGuard::try_map(inner, |component| {
+ component.downcast_mut::<DataT>()
+ })
+ .map_err(|_| HandleError::IncorrectType)?,
+ event_submitter: world.event_submitter(),
+ })
}
-}
-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>
+ pub fn set_changed(&self)
{
- let component = optional_component.unwrap_or_else(|| {
- panic!(
- "Component {} was not found in entity",
- type_name::<ComponentT>()
- );
- });
-
- Ok(Self::new(component.write_nonblock()?))
+ self.event_submitter.submit_event(
+ &Pair::new::<Changed>(self.entity_component_ref.id()),
+ self.entity_component_ref.entity_id(),
+ );
}
}
-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<DataT: 'static> Deref for HandleMut<'_, DataT>
{
- type Target = ComponentT;
+ type Target = DataT;
fn deref(&self) -> &Self::Target
{
@@ -361,7 +169,7 @@ impl<ComponentT: Component> Deref for HandleMut<'_, ComponentT>
}
}
-impl<ComponentT: Component> DerefMut for HandleMut<'_, ComponentT>
+impl<DataT: 'static> DerefMut for HandleMut<'_, DataT>
{
fn deref_mut(&mut self) -> &mut Self::Target
{
@@ -369,53 +177,35 @@ impl<ComponentT: Component> DerefMut for HandleMut<'_, ComponentT>
}
}
+#[derive(Debug, thiserror::Error)]
+pub enum HandleError
+{
+ #[error(transparent)]
+ AcquireLockFailed(#[from] AcquireLockError),
+
+ #[error("Incorrect component type")]
+ IncorrectType,
+}
+
+#[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,105 @@ 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
}
- fn added_event_ids() -> Vec<Uid>
+ #[must_use]
+ pub fn builder() -> PartsBuilder
{
- Vec::new()
+ PartsBuilder::default()
}
- fn removed_event_ids() -> Vec<Uid>
+ pub(crate) fn into_data(self) -> Box<dyn Any>
{
- Vec::new()
+ self.data
}
}
-pub trait Into
+#[derive(Debug)]
+pub struct PartsBuilder
{
- type Component;
-
- fn into_component(self) -> (Uid, Self::Component);
+ name: &'static str,
}
-impl<ComponentT> Into for ComponentT
-where
- ComponentT: Component,
+impl PartsBuilder
{
- type Component = Self;
+ #[must_use]
+ pub fn name(mut self, name: &'static str) -> Self
+ {
+ self.name = name;
+ self
+ }
- fn into_component(self) -> (Uid, Self::Component)
+ #[must_use]
+ pub fn build<Data: 'static>(self, id: Uid, data: Data) -> Parts
+ {
+ Parts {
+ id,
+ name: self.name,
+ data: Box::new(data),
+ }
+ }
+
+ #[must_use]
+ pub fn build_with_any_data(self, id: Uid, data: Box<dyn Any>) -> Parts
+ {
+ Parts { id, name: self.name, data }
+ }
+}
+
+impl Default for PartsBuilder
+{
+ fn default() -> Self
{
- (Self::id(), self)
+ Self { name: "(unspecified)" }
}
}