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.rs469
1 files changed, 243 insertions, 226 deletions
diff --git a/ecs/src/component.rs b/ecs/src/component.rs
index a9894b7..5a8cd0b 100644
--- a/ecs/src/component.rs
+++ b/ecs/src/component.rs
@@ -1,79 +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::lock::{ReadGuard, WriteGuard};
-use crate::system::{ComponentRef, ComponentRefMut, Input as SystemInput};
-use crate::type_name::TypeName;
+use crate::lock::{
+ Error as LockError,
+ MappedReadGuard,
+ MappedWriteGuard,
+ ReadGuard,
+ WriteGuard,
+};
+use crate::system::Input as SystemInput;
use crate::uid::Uid;
-use crate::{EntityComponent, World};
+use crate::util::Array;
+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>
- where
- Self: Sized;
-
- type Ref<'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;
-
- #[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>()
}
}
@@ -85,249 +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>>;
+ inner: MappedReadGuard<'a, ComponentData>,
+}
- fn id() -> 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>
{
- ComponentT::id()
+ Ok(Self::new(
+ entity_component_ref
+ .component()
+ .read_nonblock()
+ .map_err(AcquireLockError)?,
+ ))
}
- fn self_id(&self) -> Uid
+ pub(crate) fn new(inner: ReadGuard<'comp, Box<dyn Any>>) -> Self
{
- Self::id()
+ Self {
+ inner: inner.map(|component| {
+ component
+ .downcast_ref::<ComponentData>()
+ .unwrap_or_else(|| {
+ panic!(
+ "Failed to downcast component to type {}",
+ type_name::<ComponentData>()
+ );
+ })
+ }),
+ }
}
+}
+
+impl<ComponentData: 'static> Deref for Handle<'_, ComponentData>
+{
+ type Target = ComponentData;
- fn as_any_mut(&mut self) -> &mut dyn Any
+ 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>()
+ );
+ })
+ }),
+ }
}
+}
- fn is_optional() -> IsOptional
+impl<ComponentData: 'static> Deref for HandleMut<'_, ComponentData>
+{
+ type Target = ComponentData;
+
+ 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 {}
+#[derive(Debug, thiserror::Error)]
+pub enum HandleError
+{
+ #[error(transparent)]
+ AcquireLockFailed(#[from] AcquireLockError),
+}
-/// A sequence of components.
-pub trait Sequence
+#[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<#(IntoCompParts~I: IntoParts,)*> Sequence for (#(IntoCompParts~I,)*)
+ {
+ const COUNT: usize = $c + 1;
+
+ type PartsArray = [Parts; $c + 1];
+
+ fn into_parts_array(self) -> Self::PartsArray
+ {
+ [#({
+ self.I.into_parts()
+ },)*]
+ }
+ }
+ });
+ };
+}
+
+seq!(C in 0..=16 {
+ inner!(C);
+});
+
+impl Sequence for ()
{
- type MutRefs<'component>
- where
- Self: 'component;
+ type PartsArray = [Parts; 0];
- type Refs<'component>
- where
- Self: 'component;
-
- fn into_vec(self) -> Vec<Box<dyn Component>>;
-
- fn metadata() -> Vec<Metadata>;
-
- fn from_components_mut<'component>(
- components: impl Iterator<Item = &'component EntityComponent>,
- world: &'component World,
- lock_component: fn(
- entity_component: &EntityComponent,
- ) -> WriteGuard<'_, Box<dyn Component>>,
- ) -> Self::MutRefs<'component>;
-
- fn from_components<'component>(
- components: impl Iterator<Item = &'component EntityComponent>,
- world: &'component World,
- lock_component: fn(
- entity_component: &EntityComponent,
- ) -> ReadGuard<'_, Box<dyn Component>>,
- ) -> Self::Refs<'component>;
+ const COUNT: usize = 0;
+
+ fn into_parts_array(self) -> Self::PartsArray
+ {
+ []
+ }
+}
+
+pub trait IntoParts
+{
+ fn into_parts(self) -> Parts;
+}
+
+impl<ComponentT> IntoParts for ComponentT
+where
+ ComponentT: 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
+ }
+
+ #[must_use]
+ pub fn builder() -> PartsBuilder
+ {
+ PartsBuilder::default()
+ }
+
+ pub(crate) fn into_data(self) -> Box<dyn Any>
+ {
+ self.data
}
}
-/// Whether or not a `Component` is optional.
-#[derive(Debug, Clone, Copy, PartialEq, Eq)]
-pub enum IsOptional
+#[derive(Debug)]
+pub struct PartsBuilder
{
- Yes,
- No,
+ name: &'static str,
}
-impl From<bool> for IsOptional
+impl PartsBuilder
{
- fn from(is_optional: bool) -> Self
+ #[must_use]
+ pub fn name(mut self, name: &'static str) -> Self
{
- if is_optional {
- return IsOptional::Yes;
- }
+ self.name = name;
+ self
+ }
- IsOptional::No
+ #[must_use]
+ pub fn build<Data: 'static>(self, id: Uid, data: Data) -> Parts
+ {
+ Parts {
+ id,
+ name: self.name,
+ data: Box::new(data),
+ }
}
}
-pub trait FromOptionalMut<'comp>
+impl Default for PartsBuilder
{
- fn from_optional_mut_component(
- optional_component: Option<WriteGuard<'comp, Box<dyn Component>>>,
- world: &'comp World,
- ) -> Self;
+ fn default() -> Self
+ {
+ Self { name: "(unspecified)" }
+ }
}
-pub trait FromOptional<'comp>
+/// Pending component removals for a entity.
+#[derive(Debug, Clone, Component)]
+pub struct Removals
{
- fn from_optional_component(
- optional_component: Option<ReadGuard<'comp, Box<dyn Component>>>,
- world: &'comp World,
- ) -> Self;
+ component_ids: HashSet<Uid>,
}
-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>,)*
- {
- type MutRefs<'component> = (#(Comp~I::RefMut<'component>,)*)
- where Self: 'component;
-
- type Refs<'component> = (#(Comp~I::Ref<'component>,)*)
- where Self: 'component;
-
- fn into_vec(self) -> Vec<Box<dyn Component>>
- {
- Vec::from_iter([#(Box::new(self.I) as Box<dyn Component>,)*])
- }
-
- fn metadata() -> Vec<Metadata>
- {
- vec![
- #(
- Metadata {
- id: Comp~I::id(),
- is_optional: Comp~I::is_optional()
- },
- )*
- ]
- }
-
- fn from_components_mut<'component>(
- components: impl Iterator<Item = &'component EntityComponent>,
- world: &'component World,
- lock_component: fn(
- entity_component: &EntityComponent,
- ) -> WriteGuard<'_, Box<dyn Component>>,
- ) -> Self::MutRefs<'component>
- {
- #(
- let mut comp_~I: Option<WriteGuard<Box<dyn Component>>> = None;
- )*
-
- for comp in components {
- #(
- if comp.id == Comp~I::Component::id() {
- comp_~I = Some(lock_component(comp));
- continue;
- }
- )*
- }
-
- (#(
- Comp~I::RefMut::from_optional_mut_component(comp_~I, world),
- )*)
- }
+impl Removals
+{
+ pub fn contains<ComponentT: Component>(&self) -> bool
+ {
+ self.contains_id(ComponentT::id())
+ }
- fn from_components<'component>(
- components: impl Iterator<Item = &'component EntityComponent>,
- world: &'component World,
- lock_component: fn(
- entity_component: &EntityComponent,
- ) -> ReadGuard<'_, Box<dyn Component>>,
- ) -> Self::Refs<'component>
- {
+ pub fn contains_id(&self, component_id: Uid) -> bool
+ {
+ self.component_ids.contains(&component_id)
+ }
- #(
- let mut comp_~I: Option<ReadGuard<Box<dyn Component>>> = None;
- )*
-
- for comp in components {
- #(
- if comp.id == Comp~I::Component::id() {
- comp_~I = Some(lock_component(comp));
- continue;
- }
- )*
- }
-
- (#(
- Comp~I::Ref::from_optional_component(comp_~I, world),
- )*)
- }
- }
- });
- };
+ pub(crate) fn add_ids(&mut self, ids: impl IntoIterator<Item = Uid>)
+ {
+ self.component_ids.extend(ids)
+ }
}
-seq!(C in 0..=64 {
- inner!(C);
-});
+impl FromIterator<Uid> for Removals
+{
+ fn from_iter<T: IntoIterator<Item = Uid>>(iter: T) -> Self
+ {
+ Self {
+ component_ids: iter.into_iter().collect(),
+ }
+ }
+}