summaryrefslogtreecommitdiff
path: root/engine-ecs/src
diff options
context:
space:
mode:
Diffstat (limited to 'engine-ecs/src')
-rw-r--r--engine-ecs/src/lib.rs22
-rw-r--r--engine-ecs/src/system.rs33
-rw-r--r--engine-ecs/src/system/initializable.rs4
-rw-r--r--engine-ecs/src/system/observer.rs107
-rw-r--r--engine-ecs/src/system/stateful.rs86
-rw-r--r--engine-ecs/src/util.rs17
6 files changed, 119 insertions, 150 deletions
diff --git a/engine-ecs/src/lib.rs b/engine-ecs/src/lib.rs
index a60ddcd..70816b3 100644
--- a/engine-ecs/src/lib.rs
+++ b/engine-ecs/src/lib.rs
@@ -49,7 +49,7 @@ use crate::query::{
};
use crate::sole::{Single, Sole};
use crate::stats::Stats;
-use crate::system::observer::{Observer, WrapperComponent as ObserverWrapperComponent};
+use crate::system::observer::Observer;
use crate::system::{Callbacks, Metadata as SystemMetadata, System, SystemComponent};
use crate::uid::{Kind as UidKind, Uid};
@@ -163,13 +163,13 @@ impl World
) where
ObserverT: Observer<'this, SystemImpl>,
{
- let (wrapper_comp, mut system_callbacks) = observer.finish_observer();
+ let (system, mut system_callbacks) = observer.finish_observer();
let ent_id = Uid::new_unique(UidKind::Entity);
self.create_ent(
ent_id,
- [wrapper_comp.into_parts()].into_iter().chain(
+ [SystemComponent { system }.into_parts()].into_iter().chain(
ObserverT::observed_events()
.into_iter()
.map(IntoComponentParts::into_parts),
@@ -386,9 +386,11 @@ impl World
// SAFETY: The world lives long enough
if let Err(err) = unsafe {
- system
- .system
- .run(self, SystemMetadata { ent_id: system_entity.uid() })
+ system.system.run(
+ self,
+ SystemMetadata { ent_id: system_entity.uid() },
+ None,
+ )
} {
cold_path();
@@ -585,20 +587,20 @@ impl World
{
assert_eq!(event_id.kind(), UidKind::Pair);
- let query = Query::<(&ObserverWrapperComponent,)>::from_flexible_query(
+ let query = Query::<(&SystemComponent,)>::from_flexible_query(
self.flexible_query(
QueryTerms::<QUERY_MAX_TERM_CNT>::builder()
- .with_required([ObserverWrapperComponent::id(), event_id])
+ .with_required([SystemComponent::id(), event_id])
.build(),
),
);
for (observer_ent_id, (observer,)) in query.iter_with_euids() {
if let Err(err) = unsafe {
- observer.run(
+ observer.system.run(
self,
SystemMetadata { ent_id: observer_ent_id },
- emitted_event.clone(),
+ Some(emitted_event.clone()),
)
} {
cold_path();
diff --git a/engine-ecs/src/system.rs b/engine-ecs/src/system.rs
index 38e480d..5395b14 100644
--- a/engine-ecs/src/system.rs
+++ b/engine-ecs/src/system.rs
@@ -3,6 +3,7 @@ use std::fmt::Debug;
use seq_macro::seq;
use crate::error::Error;
+use crate::event::Emitted as EmittedEvent;
use crate::uid::Uid;
use crate::{Component, World};
@@ -31,7 +32,7 @@ macro_rules! impl_system {
impl<'world, Func, Ret, #(TParam~I,)*> System<'world, fn(#(TParam~I,)*) -> Ret>
for Func
where
- Func: Fn(#(TParam~I,)*) -> Ret + 'static,
+ Func: Fn(#(TParam~I,)*) -> Ret + Copy + 'static,
Ret: ReturnValue,
#(TParam~I: Param<'world, Input = ()>,)*
{
@@ -41,16 +42,23 @@ macro_rules! impl_system {
{
#![allow(unused)]
+ crate::util::const_assert!(
+ size_of::<Func>() == 0,
+ "System function is not zero-sized (not function pointer)"
+ );
+
let type_erased = TypeErased {
- run: Box::new(move |world, metadata| {
+ run: |world, metadata, _| {
// SAFETY: The caller of TypeErased::run ensures the lifetime
// is correct
let world = unsafe { &*std::ptr::from_ref(world) };
- self(#({
+ let func = unsafe { std::mem::zeroed::<Func>() };
+
+ func(#({
TParam~I::new(world, &metadata)
},)*).into_result()
- }),
+ },
name: std::any::type_name::<Self>()
};
@@ -74,8 +82,8 @@ pub trait Into<'world, Impl>
pub struct TypeErased
{
- run: Box<TypeErasedRunFn>,
- name: &'static str,
+ pub run: TypeErasedRunFn,
+ pub name: &'static str,
}
impl TypeErased
@@ -84,9 +92,14 @@ impl TypeErased
///
/// # Safety
/// `world_data` must live at least as long as the [`World`] the system belongs to.
- pub unsafe fn run(&self, world: &World, metadata: Metadata) -> Result<(), Error>
+ pub unsafe fn run(
+ &self,
+ world: &World,
+ metadata: Metadata,
+ evt: Option<EmittedEvent<'_>>,
+ ) -> Result<(), Error>
{
- (self.run)(world, metadata)
+ (self.run)(world, metadata, evt)
}
pub fn name(&self) -> &'static str
@@ -153,5 +166,5 @@ pub(crate) struct SystemComponent
pub(crate) system: TypeErased,
}
-/// Function in [`TypeErased`] used to run the system.
-type TypeErasedRunFn = dyn Fn(&World, Metadata) -> Result<(), Error>;
+type TypeErasedRunFn =
+ fn(&World, Metadata, Option<EmittedEvent<'_>>) -> Result<(), Error>;
diff --git a/engine-ecs/src/system/initializable.rs b/engine-ecs/src/system/initializable.rs
index b6ec8e8..fa925e0 100644
--- a/engine-ecs/src/system/initializable.rs
+++ b/engine-ecs/src/system/initializable.rs
@@ -2,11 +2,11 @@ use std::marker::PhantomData;
use seq_macro::seq;
-use crate::system::{Input, Param as SystemParam, System};
+use crate::system::{Input, Param as SystemParam};
use crate::tuple::{Reduce as TupleReduce, ReduceElement as TupleReduceElement, Tuple};
/// A initializable system.
-pub trait Initializable<'world, Impl>: System<'world, Impl>
+pub trait Initializable<'world, Impl>
{
type Inputs;
diff --git a/engine-ecs/src/system/observer.rs b/engine-ecs/src/system/observer.rs
index 1ad7496..e5345cd 100644
--- a/engine-ecs/src/system/observer.rs
+++ b/engine-ecs/src/system/observer.rs
@@ -7,15 +7,13 @@ use std::slice::Iter as SliceIter;
use seq_macro::seq;
use crate::entity::Handle as EntityHandle;
-use crate::error::Error;
use crate::event::Emitted as EmittedEvent;
use crate::pair::Pair;
use crate::system::{
- Metadata,
+ Callbacks,
NoCallbacks,
Param,
ReturnValue as SystemReturnValue,
- System,
TypeErased as TypeErasedSystem,
};
use crate::uid::Uid;
@@ -46,13 +44,14 @@ where
}
/// Observer system.
-pub trait Observer<'world, Impl>: System<'world, Impl>
+pub trait Observer<'world, Impl>
{
+ type Callbacks: Callbacks;
type ObservedEvents: Array<Pair<Uid, Uid>>;
fn observed_events() -> Self::ObservedEvents;
- fn finish_observer(self) -> (WrapperComponent, Self::Callbacks);
+ fn finish_observer(self) -> (TypeErasedSystem, Self::Callbacks);
}
pub struct Observe<'world, ObservedT: Observed>
@@ -155,36 +154,17 @@ impl<'world, ObservedT: Observed> EventMatch<'world, ObservedT>
macro_rules! impl_observer {
($c: tt) => {
seq!(I in 0..$c {
- impl<'world, ObservedT, Func, Ret, #(TParam~I,)*> System<
- 'world,
- fn(Observe<'world, ObservedT>, #(TParam~I,)*) -> Ret
- > for Func
- where
- ObservedT: Observed,
- Func: Fn(Observe<'world, ObservedT>, #(TParam~I,)*) -> Ret + 'static,
- Ret: SystemReturnValue,
- #(TParam~I: Param<'world, Input = ()>,)*
- {
- type Callbacks = NoCallbacks;
-
- fn finish(self) -> (TypeErasedSystem, NoCallbacks)
- {
- const {
- panic!("Observers cannot be used as regular systems");
- }
- }
- }
-
impl<'world, ObservedT, Func, Ret, #(TParam~I,)*> Observer<
'world,
fn(Observe<'world, ObservedT>, #(TParam~I,)*) -> Ret
> for Func
where
ObservedT: Observed,
- Func: Fn(Observe<'world, ObservedT>, #(TParam~I,)*) -> Ret + 'static,
+ Func: Fn(Observe<'world, ObservedT>, #(TParam~I,)*) -> Ret + Copy + 'static,
Ret: SystemReturnValue,
#(TParam~I: Param<'world, Input = ()>,)*
{
+ type Callbacks = NoCallbacks;
type ObservedEvents = ObservedT::Events;
fn observed_events() -> Self::ObservedEvents
@@ -192,16 +172,24 @@ macro_rules! impl_observer {
ObservedT::events()
}
- fn finish_observer(self) -> (WrapperComponent, NoCallbacks)
+ fn finish_observer(self) -> (TypeErasedSystem, NoCallbacks)
{
- #[allow(unused)]
+ #![allow(unused)]
- let wrapper_comp = WrapperComponent::new(
- move |world, metadata, emitted_event| {
+ crate::util::const_assert!(
+ size_of::<Func>() == 0,
+ "System function is not zero-sized (not function pointer)"
+ );
+
+ let system = TypeErasedSystem {
+ run: |world, metadata, emitted_event| {
// SAFETY: The caller of TypeErased::run ensures the lifetime
// is correct
let world = unsafe { &*std::ptr::from_ref(world) };
+ let emitted_event =
+ emitted_event.expect("No event info passed to observer");
+
// SAFETY: The caller of TypeErased::run ensures the lifetime
// is correct
let emitted_event = unsafe {
@@ -210,14 +198,16 @@ macro_rules! impl_observer {
)
};
- self(Observe::new(world, emitted_event), #({
+ let func = unsafe { std::mem::zeroed::<Func>() };
+
+ func(Observe::new(world, emitted_event), #({
TParam~I::new(world, &metadata)
},)*).into_result()
},
- type_name::<Func>()
- );
+ name: type_name::<Func>()
+ };
- (wrapper_comp, NoCallbacks)
+ (system, NoCallbacks)
}
}
});
@@ -227,52 +217,3 @@ macro_rules! impl_observer {
seq!(C in 0..16 {
impl_observer!(C);
});
-
-#[derive(Component)]
-pub struct WrapperComponent
-{
- run: Box<RunFn>,
- name: &'static str,
-}
-
-impl WrapperComponent
-{
- pub fn new(
- run: impl Fn(&World, Metadata, EmittedEvent<'_>) -> Result<(), Error> + 'static,
- name: &'static str,
- ) -> Self
- {
- Self { run: Box::new(run), name }
- }
-
- /// Runs the observer system.
- ///
- /// # Safety
- /// `world` must live at least as long as the [`World`] the system belongs to.
- pub unsafe fn run(
- &self,
- world: &World,
- metadata: Metadata,
- emitted_event: EmittedEvent<'_>,
- ) -> Result<(), Error>
- {
- (self.run)(world, metadata, emitted_event)
- }
-
- pub fn name(&self) -> &'static str
- {
- self.name
- }
-}
-
-impl Debug for WrapperComponent
-{
- fn fmt(&self, formatter: &mut std::fmt::Formatter<'_>) -> std::fmt::Result
- {
- formatter
- .debug_struct("WrapperComponent")
- .finish_non_exhaustive()
- }
-}
-
-type RunFn = dyn Fn(&World, Metadata, EmittedEvent<'_>) -> Result<(), Error>;
diff --git a/engine-ecs/src/system/stateful.rs b/engine-ecs/src/system/stateful.rs
index b73baeb..c9354c3 100644
--- a/engine-ecs/src/system/stateful.rs
+++ b/engine-ecs/src/system/stateful.rs
@@ -1,4 +1,5 @@
use std::any::type_name;
+use std::marker::PhantomData;
use std::mem::transmute;
use seq_macro::seq;
@@ -7,12 +8,7 @@ use crate::component::local::SystemWithLocalComponents;
use crate::component::Parts as ComponentParts;
use crate::event::Emitted as EmittedEvent;
use crate::system::initializable::{Initializable, MaybeInitializableParamTuple};
-use crate::system::observer::{
- Observe,
- Observed,
- Observer,
- WrapperComponent as ObserverWrapperComponent,
-};
+use crate::system::observer::{Observe, Observed, Observer};
use crate::system::{
Into as IntoSystem,
Metadata,
@@ -24,10 +20,10 @@ use crate::system::{
use crate::World;
/// A stateful system.
-pub struct Stateful<Func>
+pub struct Stateful<Func: Copy + 'static>
{
- func: Func,
local_components: Vec<ComponentParts>,
+ _pd: PhantomData<Func>,
}
macro_rules! impl_system {
@@ -36,7 +32,7 @@ macro_rules! impl_system {
impl<'world, Func, Ret, #(TParam~I,)*>
System<'world, fn(#(TParam~I,)*) -> Ret> for Stateful<Func>
where
- Func: Fn(#(TParam~I,)*) -> Ret + 'static,
+ Func: Fn(#(TParam~I,)*) -> Ret + Copy + 'static,
Ret: ReturnValue,
#(TParam~I: Param<'world, Input: 'static>,)*
{
@@ -44,22 +40,29 @@ macro_rules! impl_system {
fn finish(self) -> (TypeErased, Self::Callbacks)
{
- let Self { func, local_components } = self;
+ crate::util::const_assert!(
+ size_of::<Func>() == 0,
+ "System function is not zero-sized (not function pointer)"
+ );
+
+ let Self { local_components, .. } = self;
let callbacks = Callbacks { local_components };
let type_erased = TypeErased {
- run: Box::new(move |world, metadata| {
+ run: |world, metadata, _| {
// SAFETY: The caller of TypeErased::run ensures the lifetime
// is correct
let world = unsafe { &*std::ptr::from_ref(world) };
+ let func = unsafe { std::mem::zeroed::<Func>() };
+
func(#({
TParam~I::new(&world, &metadata)
},)*);
Ok(())
- }),
+ },
name: type_name::<Func>()
};
@@ -71,7 +74,7 @@ macro_rules! impl_system {
impl<'world, Func, Ret, #(TParam~I,)*>
Initializable<'world, fn(#(TParam~I,)*) -> Ret> for Stateful<Func>
where
- Func: Fn(#(TParam~I,)*) -> Ret + 'static,
+ Func: Fn(#(TParam~I,)*) -> Ret + Copy + 'static,
Ret: ReturnValue,
#(TParam~I: Param<'world, Input: 'static>,)*
(#(TParam~I,)*): MaybeInitializableParamTuple<'world, Self>
@@ -91,7 +94,7 @@ macro_rules! impl_system {
impl<'world, Func, Ret, #(TParam~I,)*>
IntoSystem<'world, fn(#(TParam~I,)*) -> Ret> for Func
where
- Func: Fn(#(TParam~I,)*) -> Ret + 'static,
+ Func: Fn(#(TParam~I,)*) -> Ret + Copy + 'static,
Ret: ReturnValue,
#(TParam~I: Param<'world>,)*
{
@@ -100,8 +103,8 @@ macro_rules! impl_system {
fn into_system(self) -> Self::System
{
Self::System {
- func: self,
local_components: Vec::new(), // TODO: Use Vec::with_capacity
+ _pd: PhantomData
}
}
}
@@ -113,7 +116,7 @@ seq!(C in 1..16 {
impl_system!(C);
});
-impl<Func> SystemWithLocalComponents for Stateful<Func>
+impl<Func: Copy + 'static> SystemWithLocalComponents for Stateful<Func>
{
fn add_local_component(&mut self, component_parts: ComponentParts)
{
@@ -149,31 +152,13 @@ fn init_initializable_params<'world, SystemT, Params>(
macro_rules! impl_observer {
($c: tt) => {
seq!(I in 0..$c {
- impl<'world, ObservedT, Func, Ret, #(TParam~I,)*> System<
- 'world,
- fn(Observe<'world, ObservedT>, #(TParam~I,)*) -> Ret
- > for Stateful<Func>
- where
- ObservedT: Observed,
- Func: Fn(Observe<'world, ObservedT>, #(TParam~I,)*) -> Ret + 'static,
- Ret: ReturnValue,
- #(TParam~I: Param<'world>,)*
- {
- type Callbacks = Callbacks;
-
- fn finish(self) -> (TypeErased, Callbacks)
- {
- unimplemented!();
- }
- }
-
impl<'world, ObservedT, Func, Ret, #(TParam~I,)*> Initializable<
'world,
fn(Observe<'world, ObservedT>, #(TParam~I,)*) -> Ret
> for Stateful<Func>
where
ObservedT: Observed,
- Func: Fn(Observe<'world, ObservedT>, #(TParam~I,)*) -> Ret + 'static,
+ Func: Fn(Observe<'world, ObservedT>, #(TParam~I,)*) -> Ret + Copy + 'static,
Ret: ReturnValue,
#(TParam~I: Param<'world>,)*
(#(TParam~I,)*): MaybeInitializableParamTuple<'world, Self>
@@ -196,10 +181,11 @@ macro_rules! impl_observer {
> for Stateful<Func>
where
ObservedT: Observed,
- Func: Fn(Observe<'world, ObservedT>, #(TParam~I,)*) -> Ret + 'static,
+ Func: Fn(Observe<'world, ObservedT>, #(TParam~I,)*) -> Ret + Copy + 'static,
Ret: ReturnValue,
#(TParam~I: Param<'world>,)*
{
+ type Callbacks = Callbacks;
type ObservedEvents = ObservedT::Events;
fn observed_events() -> Self::ObservedEvents
@@ -207,20 +193,28 @@ macro_rules! impl_observer {
ObservedT::events()
}
- fn finish_observer(self) -> (ObserverWrapperComponent, Callbacks)
+ fn finish_observer(self) -> (TypeErased, Callbacks)
{
#![allow(unused)]
- let Self { func, local_components } = self;
+ crate::util::const_assert!(
+ size_of::<Func>() == 0,
+ "System function is not zero-sized (not function pointer)"
+ );
+
+ let Self { local_components, .. } = self;
let callbacks = Callbacks { local_components };
- let wrapper_comp = ObserverWrapperComponent::new(
- move |world, metadata, emitted_event| {
+ let system = TypeErased {
+ run: |world, metadata, emitted_event| {
// SAFETY: The caller of TypeErased::run ensures the lifetime
// is correct
let world = unsafe { &*std::ptr::from_ref(world) };
+ let emitted_event =
+ emitted_event.expect("No event info passed to observer");
+
// SAFETY: The caller of TypeErased::run ensures the lifetime
// is correct
let emitted_event = unsafe {
@@ -229,14 +223,16 @@ macro_rules! impl_observer {
)
};
+ let func = unsafe { std::mem::zeroed::<Func>() };
+
func(Observe::new(world, emitted_event), #({
TParam~I::new(world, &metadata)
},)*).into_result()
},
- type_name::<Func>()
- );
+ name: type_name::<Func>()
+ };
- (wrapper_comp, callbacks)
+ (system, callbacks)
}
}
@@ -246,7 +242,7 @@ macro_rules! impl_observer {
> for Func
where
ObservedT: Observed,
- Func: Fn(Observe<'world, ObservedT>, #(TParam~I,)*) -> Ret + 'static,
+ Func: Fn(Observe<'world, ObservedT>, #(TParam~I,)*) -> Ret + Copy + 'static,
Ret: ReturnValue,
#(TParam~I: Param<'world>,)*
{
@@ -255,8 +251,8 @@ macro_rules! impl_observer {
fn into_system(self) -> Stateful<Func>
{
Stateful {
- func: self,
local_components: Vec::new(), // TODO: Use Vec::with_capacity
+ _pd: PhantomData
}
}
}
diff --git a/engine-ecs/src/util.rs b/engine-ecs/src/util.rs
index 27e9748..8de44e4 100644
--- a/engine-ecs/src/util.rs
+++ b/engine-ecs/src/util.rs
@@ -382,6 +382,23 @@ macro_rules! impl_multiple {
pub(crate) use impl_multiple;
+macro_rules! const_assert {
+ ($expr: expr, $message: literal) => {
+ const {
+ if !($expr) {
+ panic!(concat!(
+ "Const assertion failed: ",
+ stringify!($expr),
+ ": ",
+ $message
+ ))
+ }
+ }
+ };
+}
+
+pub(crate) use const_assert;
+
mod sealed
{
pub trait Sealed {}