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.rs289
1 files changed, 181 insertions, 108 deletions
diff --git a/ecs/src/component.rs b/ecs/src/component.rs
index a9894b7..b2ecf80 100644
--- a/ecs/src/component.rs
+++ b/ecs/src/component.rs
@@ -3,10 +3,16 @@ use std::fmt::Debug;
use seq_macro::seq;
-use crate::lock::{ReadGuard, WriteGuard};
-use crate::system::{ComponentRef, ComponentRefMut, Input as SystemInput};
+use crate::event::component::{
+ Added as ComponentAddedEvent,
+ Kind as ComponentEventKind,
+ Removed as ComponentRemovedEvent,
+};
+use crate::lock::{Error as LockError, Lock, ReadGuard, WriteGuard};
+use crate::system::Input as SystemInput;
use crate::type_name::TypeName;
use crate::uid::Uid;
+use crate::util::Array;
use crate::{EntityComponent, World};
pub mod local;
@@ -20,11 +26,11 @@ pub trait Component: SystemInput + Any + TypeName
where
Self: Sized;
- type RefMut<'component>
+ type RefMut<'component>: FromOptionalMut<'component> + FromLockedOptional<'component>
where
Self: Sized;
- type Ref<'component>
+ type Ref<'component>: FromOptional<'component> + FromLockedOptional<'component>
where
Self: Sized;
@@ -36,26 +42,28 @@ pub trait Component: SystemInput + Any + TypeName
/// 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
+ /// Returns whether the component `self` is optional.
+ fn self_is_optional(&self) -> bool
{
- IsOptional::No
+ false
}
/// Returns whether this component is optional.
#[must_use]
- fn is_optional() -> IsOptional
+ fn is_optional() -> bool
where
Self: Sized,
{
- IsOptional::No
+ false
}
}
@@ -96,10 +104,12 @@ impl TypeName for Box<dyn Component>
impl<ComponentT> Component for Option<ComponentT>
where
ComponentT: Component,
+ for<'a> Option<ComponentT::Ref<'a>>: FromOptional<'a> + FromLockedOptional<'a>,
+ for<'a> Option<ComponentT::RefMut<'a>>: FromOptionalMut<'a> + FromLockedOptional<'a>,
{
type Component = ComponentT;
- type Ref<'component> = Option<ComponentRef<'component, ComponentT>>;
- type RefMut<'component> = Option<ComponentRefMut<'component, ComponentT>>;
+ type Ref<'component> = Option<ComponentT::Ref<'component>>;
+ type RefMut<'component> = Option<ComponentT::RefMut<'component>>;
fn id() -> Uid
{
@@ -111,6 +121,13 @@ where
Self::id()
}
+ fn get_event_uid(&self, event_kind: ComponentEventKind) -> Uid
+ {
+ match event_kind {
+ ComponentEventKind::Removed => ComponentRemovedEvent::<Self>::id(),
+ }
+ }
+
fn as_any_mut(&mut self) -> &mut dyn Any
{
self
@@ -121,14 +138,14 @@ where
self
}
- fn self_is_optional(&self) -> IsOptional
+ fn self_is_optional(&self) -> bool
{
- Self::is_optional()
+ true
}
- fn is_optional() -> IsOptional
+ fn is_optional() -> bool
{
- IsOptional::Yes
+ true
}
}
@@ -147,33 +164,57 @@ impl<ComponentT> SystemInput for Option<ComponentT> where ComponentT: Component
/// A sequence of components.
pub trait Sequence
{
- type MutRefs<'component>
- where
- Self: 'component;
+ /// The number of components in this component sequence.
+ const COUNT: usize;
- type Refs<'component>
- where
- Self: 'component;
+ type Array: Array<Box<dyn Component>>;
- fn into_vec(self) -> Vec<Box<dyn Component>>;
+ fn into_array(self) -> Self::Array;
- fn metadata() -> Vec<Metadata>;
+ fn metadata() -> impl Array<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 added_event_ids() -> Vec<Uid>;
+
+ fn removed_event_ids() -> Vec<Uid>;
+}
+
+/// A sequence of references (immutable or mutable) to components.
+pub trait RefSequence
+{
+ type Handles<'component>;
+
+ type Metadata: Array<Metadata>;
+
+ fn metadata() -> Self::Metadata;
fn from_components<'component>(
- components: impl Iterator<Item = &'component EntityComponent>,
+ components: &'component [EntityComponent],
+ component_index_lookup: impl Fn(Uid) -> Option<usize>,
world: &'component World,
- lock_component: fn(
- entity_component: &EntityComponent,
- ) -> ReadGuard<'_, Box<dyn Component>>,
- ) -> Self::Refs<'component>;
+ ) -> Self::Handles<'component>;
+}
+
+/// 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::Ref<'component>;
+}
+
+impl<ComponentT> Ref for &mut ComponentT
+where
+ ComponentT: Component,
+{
+ type Component = ComponentT;
+ type Handle<'component> = ComponentT::RefMut<'component>;
}
/// [`Component`] metadata.
@@ -182,7 +223,7 @@ pub trait Sequence
pub struct Metadata
{
pub id: Uid,
- pub is_optional: IsOptional,
+ pub is_optional: bool,
}
impl Metadata
@@ -204,26 +245,6 @@ impl Metadata
}
}
-/// 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
- {
- if is_optional {
- return IsOptional::Yes;
- }
-
- IsOptional::No
- }
-}
-
pub trait FromOptionalMut<'comp>
{
fn from_optional_mut_component(
@@ -240,6 +261,14 @@ pub trait FromOptional<'comp>
) -> Self;
}
+pub trait FromLockedOptional<'comp>: Sized
+{
+ fn from_locked_optional_component(
+ optional_component: Option<&'comp Lock<Box<dyn Component>>>,
+ world: &'comp World,
+ ) -> Result<Self, LockError>;
+}
+
macro_rules! inner {
($c: tt) => {
seq!(I in 0..=$c {
@@ -248,79 +277,76 @@ macro_rules! inner {
#(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;
+ const COUNT: usize = $c + 1;
- type Refs<'component> = (#(Comp~I::Ref<'component>,)*)
- where Self: 'component;
+ type Array = [Box<dyn Component>; $c + 1];
- fn into_vec(self) -> Vec<Box<dyn Component>>
+ fn into_array(self) -> Self::Array
{
- Vec::from_iter([#(Box::new(self.I) as Box<dyn Component>,)*])
+ [#(Box::new(self.I) as Box<dyn Component>,)*]
}
- fn metadata() -> Vec<Metadata>
+ fn metadata() -> impl Array<Metadata>
{
- vec![
+ [
#(
Metadata {
id: Comp~I::id(),
- is_optional: Comp~I::is_optional()
+ 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>
+ fn added_event_ids() -> Vec<Uid>
+ {
+ vec![
+ #(ComponentAddedEvent::<Comp~I>::id(),)*
+ ]
+ }
+
+ fn removed_event_ids() -> Vec<Uid>
{
- #(
- let mut comp_~I: Option<WriteGuard<Box<dyn Component>>> = None;
- )*
+ vec![
+ #(ComponentRemovedEvent::<Comp~I>::id(),)*
+ ]
+ }
+ }
- for comp in components {
- #(
- if comp.id == Comp~I::Component::id() {
- comp_~I = Some(lock_component(comp));
- continue;
- }
- )*
- }
+ impl<#(CompRef~I: Ref,)*> RefSequence for (#(CompRef~I,)*)
+ {
+ type Handles<'component> = (#(CompRef~I::Handle<'component>,)*);
- (#(
- Comp~I::RefMut::from_optional_mut_component(comp_~I, world),
- )*)
+ 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: impl Iterator<Item = &'component EntityComponent>,
+ components: &'component [EntityComponent],
+ component_index_lookup: impl Fn(Uid) -> Option<usize>,
world: &'component World,
- lock_component: fn(
- entity_component: &EntityComponent,
- ) -> ReadGuard<'_, Box<dyn Component>>,
- ) -> Self::Refs<'component>
+ ) -> Self::Handles<'component>
{
-
- #(
- 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),
+ 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>()
+ );
+ }),
)*)
}
}
@@ -328,6 +354,53 @@ macro_rules! inner {
};
}
-seq!(C in 0..=64 {
+seq!(C in 0..=16 {
inner!(C);
});
+
+impl Sequence for ()
+{
+ type Array = [Box<dyn Component>; 0];
+
+ const COUNT: usize = 0;
+
+ fn into_array(self) -> Self::Array
+ {
+ []
+ }
+
+ fn metadata() -> impl Array<Metadata>
+ {
+ []
+ }
+
+ fn added_event_ids() -> Vec<Uid>
+ {
+ Vec::new()
+ }
+
+ fn removed_event_ids() -> Vec<Uid>
+ {
+ Vec::new()
+ }
+}
+
+impl RefSequence for ()
+{
+ 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>
+ {
+ ()
+ }
+}