diff options
Diffstat (limited to 'ecs/src')
-rw-r--r-- | ecs/src/actions.rs | 41 | ||||
-rw-r--r-- | ecs/src/component.rs | 28 | ||||
-rw-r--r-- | ecs/src/event.rs | 95 | ||||
-rw-r--r-- | ecs/src/event/component.rs | 54 | ||||
-rw-r--r-- | ecs/src/event/start.rs | 7 | ||||
-rw-r--r-- | ecs/src/extension.rs | 16 | ||||
-rw-r--r-- | ecs/src/lib.rs | 311 | ||||
-rw-r--r-- | ecs/src/phase.rs | 15 | ||||
-rw-r--r-- | ecs/src/relationship.rs | 8 | ||||
-rw-r--r-- | ecs/src/system.rs | 7 |
10 files changed, 278 insertions, 304 deletions
diff --git a/ecs/src/actions.rs b/ecs/src/actions.rs index f7b00d3..35e9569 100644 --- a/ecs/src/actions.rs +++ b/ecs/src/actions.rs @@ -20,36 +20,45 @@ pub struct Actions<'world> impl<'world> Actions<'world> { - /// Adds a spawning a new entity to the action queue. + /// Queues up a entity to spawn at the end of the current tick. pub fn spawn<Comps: ComponentSequence>(&mut self, components: Comps) { - self.action_queue.push(Action::Spawn(components.into_vec())); + self.action_queue.push(Action::Spawn( + components.into_vec(), + EventIds { ids: Comps::added_event_ids() }, + )); } - /// Adds component(s) to a entity. + /// Queues up adding component(s) to a entity at the end of the current tick. pub fn add_components<Comps>(&mut self, entity_uid: Uid, components: Comps) where Comps: ComponentSequence, { debug_assert_eq!(entity_uid.kind(), UidKind::Entity); - self.action_queue - .push(Action::AddComponents(entity_uid, components.into_vec())); + self.action_queue.push(Action::AddComponents( + entity_uid, + components.into_vec(), + EventIds { ids: Comps::added_event_ids() }, + )); } - /// Removes component(s) from a entity. + /// Queues up removing component(s) from a entity at the end of the current tick. pub fn remove_components<Comps>(&mut self, entity_uid: Uid) where Comps: ComponentSequence, { debug_assert_eq!(entity_uid.kind(), UidKind::Entity); - self.action_queue - .push(Action::RemoveComponents(entity_uid, Comps::metadata())); + self.action_queue.push(Action::RemoveComponents( + entity_uid, + Comps::metadata(), + EventIds { ids: Comps::removed_event_ids() }, + )); } - /// Adds stopping the loop in [`Engine::event_loop`] at the next opportune time to the - /// action queue. + /// Stops the [`World`]. The world will finish the current tick and that tick will be + /// the last. pub fn stop(&mut self) { self.action_queue.push(Action::Stop); @@ -135,12 +144,18 @@ impl<'weak_ref> Ref<'weak_ref> } } +#[derive(Debug)] +pub(crate) struct EventIds +{ + pub(crate) ids: Vec<Uid>, +} + /// A action for a [`System`] to perform. #[derive(Debug)] pub(crate) enum Action { - Spawn(Vec<Box<dyn Component>>), - AddComponents(Uid, Vec<Box<dyn Component>>), - RemoveComponents(Uid, Vec<ComponentMetadata>), + Spawn(Vec<Box<dyn Component>>, EventIds), + AddComponents(Uid, Vec<Box<dyn Component>>, EventIds), + RemoveComponents(Uid, Vec<ComponentMetadata>, EventIds), Stop, } diff --git a/ecs/src/component.rs b/ecs/src/component.rs index a9894b7..0f64695 100644 --- a/ecs/src/component.rs +++ b/ecs/src/component.rs @@ -3,6 +3,10 @@ use std::fmt::Debug; use seq_macro::seq; +use crate::event::component::{ + Added as ComponentAddedEvent, + Removed as ComponentRemovedEvent, +}; use crate::lock::{ReadGuard, WriteGuard}; use crate::system::{ComponentRef, ComponentRefMut, Input as SystemInput}; use crate::type_name::TypeName; @@ -20,11 +24,11 @@ pub trait Component: SystemInput + Any + TypeName where Self: Sized; - type RefMut<'component> + type RefMut<'component>: FromOptionalMut<'component> where Self: Sized; - type Ref<'component> + type Ref<'component>: FromOptional<'component> where Self: Sized; @@ -159,6 +163,10 @@ pub trait Sequence fn metadata() -> Vec<Metadata>; + fn added_event_ids() -> Vec<Uid>; + + fn removed_event_ids() -> Vec<Uid>; + fn from_components_mut<'component>( components: impl Iterator<Item = &'component EntityComponent>, world: &'component World, @@ -265,12 +273,26 @@ macro_rules! inner { #( Metadata { id: Comp~I::id(), - is_optional: Comp~I::is_optional() + 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(),)* + ] + } + fn from_components_mut<'component>( components: impl Iterator<Item = &'component EntityComponent>, world: &'component World, diff --git a/ecs/src/event.rs b/ecs/src/event.rs index 1a4edcc..9cea807 100644 --- a/ecs/src/event.rs +++ b/ecs/src/event.rs @@ -1,96 +1 @@ -use std::any::TypeId; -use std::fmt::Debug; -use std::hash::{DefaultHasher, Hash, Hasher}; - -use seq_macro::seq; - pub mod component; - -pub trait Event: Debug + 'static -{ - /// Returns the ID of this event. - #[must_use] - fn id() -> Id - where - Self: Sized, - { - Id::new::<Self, ()>(None) - } -} - -pub mod start; - -/// The ID of a [`Event`]. -#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] -pub struct Id -{ - inner: TypeId, - extra: Option<u64>, -} - -impl Id -{ - #[must_use] - pub fn new<EventT, Extra>(extra: Option<Extra>) -> Self - where - EventT: Event, - Extra: Hash, - { - Self { - inner: TypeId::of::<EventT>(), - extra: extra.map(|extra| { - let mut hasher = DefaultHasher::new(); - - extra.hash(&mut hasher); - - hasher.finish() - }), - } - } -} - -pub trait Ids -{ - type Iter<'a>: Iterator<Item = &'a Id> - where - Self: 'a; - - fn iter(&self) -> Self::Iter<'_>; -} - -/// A sequence of events. -pub trait Sequence -{ - type Ids: Ids; - - fn ids() -> Self::Ids; -} - -macro_rules! impl_sequence { - ($c: tt) => { - seq!(I in 0..=$c { - impl Ids for [Id; $c + 1] - { - type Iter<'a> = std::slice::Iter<'a, Id>; - - fn iter(&self) -> Self::Iter<'_> { - self.into_iter() - } - } - - impl<#(Event~I: Event,)*> Sequence for (#(Event~I,)*) { - type Ids = [Id; $c + 1]; - - fn ids() -> Self::Ids { - [#( - Event~I::id(), - )*] - } - } - }); - }; -} - -seq!(C in 0..=64 { - impl_sequence!(C); -}); diff --git a/ecs/src/event/component.rs b/ecs/src/event/component.rs index 8b066a7..5b40c39 100644 --- a/ecs/src/event/component.rs +++ b/ecs/src/event/component.rs @@ -6,13 +6,11 @@ use std::marker::PhantomData; use ecs_macros::Component; use crate::component::Component; -use crate::uid::Uid; -use crate::event::{Event, Id}; -use crate::tuple::{ReduceElement as TupleReduceElement, With as TupleWith}; /// Event emitted when: /// a) A entity with component `ComponentT` is spawned. /// b) A component `ComponentT` is added to a entity. +#[derive(Clone, Component)] pub struct Added<ComponentT> where ComponentT: Component, @@ -43,19 +41,8 @@ where } } -impl<ComponentT> Event for Added<ComponentT> -where - ComponentT: Component, -{ - fn id() -> Id - where - Self: Sized, - { - Id::new::<Added<ComponentForId>, _>(Some(ComponentT::id())) - } -} - /// Event emitted when a `ComponentT` component is removed from a entity. +#[derive(Clone, Component)] pub struct Removed<ComponentT> where ComponentT: Component, @@ -85,40 +72,3 @@ where Self { _pd: PhantomData } } } - -impl<ComponentT> Event for Removed<ComponentT> -where - ComponentT: Component, -{ - fn id() -> Id - where - Self: Sized, - { - Id::new::<Removed<ComponentForId>, _>(Some(ComponentT::id())) - } -} - -#[must_use] -pub fn create_added_id(component_id: Uid) -> Id -{ - Id::new::<Added<ComponentForId>, _>(Some(component_id)) -} - -#[must_use] -pub fn create_removed_id(component_id: Uid) -> Id -{ - Id::new::<Removed<ComponentForId>, _>(Some(component_id)) -} - -pub struct TypeTransformComponentsToAddedEvents; - -impl<ComponentT: Component, Accumulator> - TupleReduceElement<Accumulator, TypeTransformComponentsToAddedEvents> for ComponentT -where - Accumulator: TupleWith<Added<Self>>, -{ - type Return = Accumulator::With; -} - -#[derive(Debug, Component)] -struct ComponentForId; diff --git a/ecs/src/event/start.rs b/ecs/src/event/start.rs deleted file mode 100644 index 248dd50..0000000 --- a/ecs/src/event/start.rs +++ /dev/null @@ -1,7 +0,0 @@ -use crate::event::Event; - -/// Start event. -#[derive(Debug, Clone, Copy)] -pub struct Start; - -impl Event for Start {} diff --git a/ecs/src/extension.rs b/ecs/src/extension.rs index a945d89..42ebef9 100644 --- a/ecs/src/extension.rs +++ b/ecs/src/extension.rs @@ -1,9 +1,7 @@ use crate::component::Sequence as ComponentSequence; -use crate::event::component::TypeTransformComponentsToAddedEvents; -use crate::event::{Event, Sequence as EventSequence}; use crate::sole::Sole; use crate::system::System; -use crate::tuple::Reduce as TupleReduce; +use crate::uid::Uid; use crate::{SoleAlreadyExistsError, World}; /// A collection of systems, entities & soles that can be added to a [`World`]. @@ -27,21 +25,19 @@ impl<'world> Collector<'world> } /// Adds a system to the [`World`]. - pub fn add_system<'this, EventT, SystemImpl>( + pub fn add_system<'this, SystemImpl>( &'this mut self, - event: EventT, + phase_euid: Uid, system: impl System<'this, SystemImpl>, - ) where - EventT: Event, + ) { - self.world.register_system(event, system); + self.world.register_system(phase_euid, system); } /// Adds a entity to the [`World`]. pub fn add_entity<Comps>(&mut self, components: Comps) where - Comps: ComponentSequence + TupleReduce<TypeTransformComponentsToAddedEvents>, - Comps::Out: EventSequence, + Comps: ComponentSequence, { self.world.create_entity(components); } diff --git a/ecs/src/lib.rs b/ecs/src/lib.rs index 78e526f..01e0cde 100644 --- a/ecs/src/lib.rs +++ b/ecs/src/lib.rs @@ -10,22 +10,21 @@ use std::sync::Arc; use crate::actions::Action; use crate::component::storage::Storage as ComponentStorage; -use crate::component::{Component, Sequence as ComponentSequence}; -use crate::entity::CREATE_STATIC_ENTITIES; -use crate::event::component::{ - create_added_id as create_component_added_event_id, - create_removed_id as create_component_removed_event_id, - TypeTransformComponentsToAddedEvents, +use crate::component::{ + Component, + IsOptional as ComponentIsOptional, + Metadata as ComponentMetadata, + Sequence as ComponentSequence, }; -use crate::event::start::Start as StartEvent; -use crate::event::{Event, Id as EventId, Ids, Sequence as EventSequence}; +use crate::entity::CREATE_STATIC_ENTITIES; use crate::extension::{Collector as ExtensionCollector, Extension}; use crate::lock::{Lock, WriteGuard}; -use crate::query::options::Options as QueryOptions; +use crate::phase::{Phase, START as START_PHASE}; +use crate::query::options::{Not, Options as QueryOptions, With}; +use crate::relationship::{ChildOf, DependsOn, Relationship}; use crate::sole::Sole; use crate::stats::Stats; -use crate::system::{System, TypeErased as TypeErasedSystem}; -use crate::tuple::Reduce as TupleReduce; +use crate::system::{System, SystemComponent}; use crate::type_name::TypeName; use crate::uid::{Kind as UidKind, Uid}; @@ -35,6 +34,7 @@ pub mod entity; pub mod event; pub mod extension; pub mod lock; +pub mod phase; pub mod query; pub mod relationship; pub mod sole; @@ -57,9 +57,9 @@ pub use crate::query::Query; #[derive(Debug, Default)] pub struct World { - systems: Vec<TypeErasedSystem>, data: WorldData, stop: AtomicBool, + is_first_tick: AtomicBool, } impl World @@ -71,6 +71,10 @@ impl World world.add_sole(Stats::default()).ok(); + for create_static_entity in CREATE_STATIC_ENTITIES { + create_static_entity(&world); + } + world } @@ -80,8 +84,7 @@ impl World /// Will panic if mutable internal lock cannot be acquired. pub fn create_entity<Comps>(&mut self, components: Comps) -> Uid where - Comps: ComponentSequence + TupleReduce<TypeTransformComponentsToAddedEvents>, - Comps::Out: EventSequence, + Comps: ComponentSequence, { let entity_uid = Uid::new_unique(UidKind::Entity); @@ -94,8 +97,7 @@ impl World #[doc(hidden)] pub fn create_entity_with_uid<Comps>(&self, components: Comps, entity_uid: Uid) where - Comps: ComponentSequence + TupleReduce<TypeTransformComponentsToAddedEvents>, - Comps::Out: EventSequence, + Comps: ComponentSequence, { debug_assert_eq!(entity_uid.kind(), UidKind::Entity); @@ -113,8 +115,8 @@ impl World return; }; - for component_added_event_id in <Comps::Out as EventSequence>::ids().iter() { - self.emit_event_by_id(*component_added_event_id); + for added_event_id in Comps::added_event_ids() { + self.emit_event_by_id(added_event_id); } } @@ -129,22 +131,29 @@ impl World self.data.sole_storage.insert(sole) } - pub fn register_system<'this, EventT, SystemImpl>( + pub fn register_system<'this, SystemImpl>( &'this mut self, - event: EventT, + phase_euid: Uid, system: impl System<'this, SystemImpl>, - ) where - EventT: Event, + ) { - self.systems.push(system.into_type_erased()); - - self.data - .events - .entry(EventT::id()) - .or_default() - .push(self.systems.len() - 1); + self.create_entity(( + SystemComponent { system: system.into_type_erased() }, + Relationship::<DependsOn, Phase>::new(phase_euid), + )); + } - drop(event); + pub fn register_observer_system<'this, SystemImpl, Event>( + &'this mut self, + system: impl System<'this, SystemImpl>, + event: Event, + ) where + Event: Component, + { + self.create_entity::<(SystemComponent, Event)>(( + SystemComponent { system: system.into_type_erased() }, + event, + )); } /// Adds a extensions. @@ -158,20 +167,6 @@ impl World extension.collect(extension_collector); } - /// Emits a event, running all systems listening to the event for each compatible - /// entity. - /// - /// # Panics - /// Will panic if a system has dissapeared. - pub fn emit<EventT>(&self, event: EventT) - where - EventT: Event, - { - self.emit_event_by_id(EventT::id()); - - drop(event); - } - pub fn query<Comps, OptionsT>(&self) -> Query<Comps, OptionsT> where Comps: ComponentSequence, @@ -180,12 +175,121 @@ impl World Query::new(self) } - /// Peforms the actions that have been queued up using [`Actions`]. + /// Performs a single tick. + /// + /// # Panics + /// Will panic if a internal lock cannot be acquired. + pub fn step(&self) -> StepResult + { + if self.stop.load(Ordering::Relaxed) { + return StepResult::Stop; + } + + if self + .is_first_tick + .compare_exchange(false, true, Ordering::Relaxed, Ordering::Relaxed) + .is_ok() + { + self.query_and_run_systems(*START_PHASE); + } + + self.perform_phases(); + + self.perform_queued_actions(); + + if self.stop.load(Ordering::Relaxed) { + return StepResult::Stop; + } + + let mut stats_lock = self + .data + .sole_storage + .get::<Stats>() + .expect("No stats sole found") + .write_nonblock() + .expect("Failed to aquire read-write stats sole lock"); + + let stats = stats_lock + .downcast_mut::<Stats>() + .expect("Casting stats sole to Stats type failed"); + + stats.current_tick += 1; + + StepResult::Continue + } + + /// Starts a loop which calls [`Self::step`] until the world is stopped. /// /// # Panics - /// Will panic if a mutable internal lock cannot be acquired. + /// Will panic if a internal lock cannot be acquired. + pub fn start_loop(&self) + { + while let StepResult::Continue = self.step() {} + } + + fn query_and_run_systems(&self, phase_euid: Uid) + { + let system_comps_query = + self.query::<(SystemComponent, Relationship<DependsOn, Phase>), ()>(); + + let system_iter = system_comps_query.iter().filter(|(_, phase_rel)| { + phase_rel + .target_uids() + .any(|target_uid| target_uid == phase_euid) + }); + + for (system_component, _) in system_iter { + // SAFETY: The world lives long enough + unsafe { + system_component.system.run(self); + } + } + } + + fn perform_child_phases(&self, parent_phase_euid: Uid) + { + let phase_query = self.query::<(Phase, Relationship<ChildOf, Phase>), ()>(); + + for (index, (_, phase_rel)) in phase_query.iter().enumerate() { + if !phase_rel + .target_uids() + .any(|phase_euid| phase_euid == parent_phase_euid) + { + continue; + } + + let phase_euid = phase_query + .get_entity_uid(index) + .expect("Cannot get current query iteration entity UID"); + + self.query_and_run_systems(phase_euid); + + self.perform_child_phases(phase_euid); + } + } + + fn perform_phases(&self) + { + let phase_query = + self.query::<(Phase,), Not<With<Relationship<ChildOf, Phase>>>>(); + + for (index, (_,)) in phase_query.iter().enumerate() { + let child_phase_euid = phase_query + .get_entity_uid(index) + .expect("Cannot get current query iteration entity UID"); + + if child_phase_euid == *START_PHASE { + continue; + } + + self.query_and_run_systems(child_phase_euid); + + self.perform_child_phases(child_phase_euid); + } + } + #[cfg_attr(feature = "debug", tracing::instrument(skip_all))] - pub fn perform_queued_actions(&self) + fn perform_queued_actions(&self) { let mut active_action_queue = match *self.data.action_queue.active_queue.borrow() { @@ -204,14 +308,9 @@ impl World for action in active_action_queue.drain(..) { match action { - Action::Spawn(components) => { + Action::Spawn(components, component_added_event_ids) => { let mut component_storage_lock = self.lock_component_storage_rw(); - let component_ids = components - .iter() - .map(|component| component.self_id()) - .collect::<Vec<_>>(); - #[allow(unused_variables)] if let Err(err) = component_storage_lock .push_entity(Uid::new_unique(UidKind::Entity), components) @@ -228,20 +327,17 @@ impl World self.swap_event_queue(&mut has_swapped_active_queue); } - for component_id in component_ids { - self.emit_event_by_id(create_component_added_event_id( - component_id, - )); + for comp_added_event_id in component_added_event_ids.ids { + self.emit_event_by_id(comp_added_event_id); } } - Action::AddComponents(entity_uid, components) => { + Action::AddComponents( + entity_uid, + components, + component_added_event_ids, + ) => { let mut component_storage_lock = self.lock_component_storage_rw(); - let component_ids = components - .iter() - .map(|component| component.self_id()) - .collect::<Vec<_>>(); - component_storage_lock .add_components_to_entity(entity_uid, components); @@ -251,13 +347,15 @@ impl World self.swap_event_queue(&mut has_swapped_active_queue); } - for component_id in component_ids { - self.emit_event_by_id(create_component_added_event_id( - component_id, - )); + for comp_added_event_id in component_added_event_ids.ids { + self.emit_event_by_id(comp_added_event_id); } } - Action::RemoveComponents(entity_uid, components_metadata) => { + Action::RemoveComponents( + entity_uid, + components_metadata, + component_removed_event_ids, + ) => { let mut component_storage_lock = self.lock_component_storage_rw(); component_storage_lock.remove_components_from_entity( @@ -273,10 +371,8 @@ impl World self.swap_event_queue(&mut has_swapped_active_queue); } - for component_metadata in components_metadata { - self.emit_event_by_id(create_component_removed_event_id( - component_metadata.id, - )); + for comp_removed_event_id in component_removed_event_ids.ids { + self.emit_event_by_id(comp_removed_event_id); } } Action::Stop => { @@ -286,60 +382,18 @@ impl World } } - /// A event loop which runs until a stop is issued with [`Flags::stop`]. Before the - /// loop begins, [`StartEvent`] is emitted. - /// - /// # Panics - /// Will panic if a internal lock cannot be acquired. - pub fn event_loop<EventSeq: EventSequence>(&self) + fn emit_event_by_id(&self, event_id: Uid) { - for create_static_entity in CREATE_STATIC_ENTITIES { - create_static_entity(self); - } - - self.emit(StartEvent); - - let event_seq = EventSeq::ids(); - - loop { - for event_id in event_seq.iter() { - self.emit_event_by_id(*event_id); - } - - self.perform_queued_actions(); - - if self.stop.load(Ordering::Relaxed) { - break; - } - - let mut stats_lock = self - .data - .sole_storage - .get::<Stats>() - .expect("No stats sole found") - .write_nonblock() - .expect("Failed to aquire read-write stats sole lock"); - - let stats = stats_lock - .downcast_mut::<Stats>() - .expect("Casting stats sole to Stats type failed"); - - stats.current_tick += 1; - } - } - - fn emit_event_by_id(&self, event_id: EventId) - { - let Some(system_indices) = self.data.events.get(&event_id) else { - return; - }; - - for system_index in system_indices { - let system = self.systems.get(*system_index).unwrap(); - + for (system,) in self + .query::<(SystemComponent,), ()>() + .iter_with_extra_comps([ComponentMetadata { + id: event_id, + is_optional: ComponentIsOptional::No, + }]) + { // SAFETY: The world lives long enough unsafe { - system.run(self); + system.system.run(self); } } } @@ -365,10 +419,19 @@ impl World } } +/// The result of calling [`World::step`]. +pub enum StepResult +{ + /// Another step can be made. + Continue, + + /// The world have been stopped so no step can be made again. + Stop, +} + #[derive(Debug, Default)] pub struct WorldData { - events: HashMap<EventId, Vec<usize>>, component_storage: Arc<Lock<ComponentStorage>>, sole_storage: SoleStorage, action_queue: Arc<ActionQueue>, diff --git a/ecs/src/phase.rs b/ecs/src/phase.rs new file mode 100644 index 0000000..b8660f2 --- /dev/null +++ b/ecs/src/phase.rs @@ -0,0 +1,15 @@ +use ecs_macros::Component; + +use crate::relationship::{ChildOf, Relationship}; +use crate::static_entity; + +#[derive(Debug, Default, Clone, Copy, Component)] +pub struct Phase; + +static_entity!(pub START, (Phase,)); + +static_entity!(pub PRE_UPDATE, (Phase,)); + +static_entity!(pub UPDATE, (Phase, <Relationship<ChildOf, Phase>>::new(*PRE_UPDATE))); + +static_entity!(pub PRESENT, (Phase, <Relationship<ChildOf, Phase>>::new(*UPDATE))); diff --git a/ecs/src/relationship.rs b/ecs/src/relationship.rs index 44ed93a..7088613 100644 --- a/ecs/src/relationship.rs +++ b/ecs/src/relationship.rs @@ -422,3 +422,11 @@ where self.relation.get(index) } } + +/// Relationship kind denoting a dependency to another entity +#[derive(Debug, Default, Clone, Copy)] +pub struct DependsOn; + +/// Relationship kind denoting being the child of another entity. +#[derive(Debug, Default, Clone, Copy)] +pub struct ChildOf; diff --git a/ecs/src/system.rs b/ecs/src/system.rs index 046d25b..3ba693b 100644 --- a/ecs/src/system.rs +++ b/ecs/src/system.rs @@ -5,6 +5,7 @@ use std::marker::PhantomData; use std::ops::{Deref, DerefMut}; use std::panic::{RefUnwindSafe, UnwindSafe}; +use ecs_macros::Component; use seq_macro::seq; use crate::component::{ @@ -314,3 +315,9 @@ impl<'a, ComponentT: Component> Deref for ComponentRef<'a, ComponentT> self.inner.downcast_ref().unwrap() } } + +#[derive(Debug, Component)] +pub(crate) struct SystemComponent +{ + pub(crate) system: TypeErased, +} |