summaryrefslogtreecommitdiff
path: root/ecs/src/system.rs
diff options
context:
space:
mode:
authorHampusM <hampus@hampusmat.com>2024-03-12 20:54:42 +0100
committerHampusM <hampus@hampusmat.com>2024-03-12 20:54:42 +0100
commit01066718b0f13846587d26b1869f03e3713082c6 (patch)
tree0ef39b49b26330ab1ed2526105a15c7a0cba7c85 /ecs/src/system.rs
parent251beb34720d2e7d60ceaddc811a65f52f15bdbd (diff)
feat(ecs): make components internally mutable
Diffstat (limited to 'ecs/src/system.rs')
-rw-r--r--ecs/src/system.rs104
1 files changed, 77 insertions, 27 deletions
diff --git a/ecs/src/system.rs b/ecs/src/system.rs
index 96f0254..76db2b5 100644
--- a/ecs/src/system.rs
+++ b/ecs/src/system.rs
@@ -1,7 +1,9 @@
use std::any::Any;
+use std::cell::RefMut;
use std::convert::Infallible;
use std::fmt::Debug;
-use std::ptr::addr_of_mut;
+use std::ops::{Deref, DerefMut};
+use std::ptr::addr_of;
use seq_macro::seq;
@@ -14,20 +16,22 @@ pub mod stateful;
mod util;
-pub trait System<Impl>: 'static
+pub trait System<'world, Impl>: 'static
{
type Input;
#[must_use]
fn initialize(self, input: Self::Input) -> Self;
- fn run(&mut self, world_data: &mut WorldData);
+ fn run<'this>(&'this self, world_data: &'world WorldData)
+ where
+ 'this: 'world;
fn into_type_erased(self) -> TypeErased;
fn get_local_component_mut<LocalComponent: Component>(
- &mut self,
- ) -> Option<&mut LocalComponent>;
+ &self,
+ ) -> Option<ComponentRefMut<LocalComponent>>;
fn set_local_component<LocalComponent: Component>(
&mut self,
@@ -38,7 +42,7 @@ pub trait System<Impl>: 'static
macro_rules! impl_system {
($c: tt) => {
seq!(I in 0..$c {
- impl<'world, Func, #(TParam~I,)*> System<fn(#(TParam~I,)*)>
+ impl<'world, Func, #(TParam~I,)*> System<'world, fn(#(TParam~I,)*)>
for Func
where
Func: Fn(#(TParam~I,)*) + Copy + 'static,
@@ -51,7 +55,9 @@ macro_rules! impl_system {
self
}
- fn run(&mut self, world_data: &mut WorldData)
+ fn run<'this>(&'this self, world_data: &'world WorldData)
+ where
+ 'this: 'world
{
#(
check_params_are_compatible!(I, TParam~I, $c);
@@ -60,17 +66,7 @@ macro_rules! impl_system {
let func = *self;
func(#({
- // SAFETY: All parameters are compatible so this is fine
- let this = unsafe {
- &mut *addr_of_mut!(*self)
- };
-
- // SAFETY: All parameters are compatible so this is fine
- let world_data = unsafe {
- &mut *addr_of_mut!(*world_data)
- };
-
- TParam~I::new(this, world_data)
+ TParam~I::new(self, world_data)
},)*);
}
@@ -79,7 +75,19 @@ macro_rules! impl_system {
TypeErased {
data: Box::new(self),
func: Box::new(|data, world_data| {
- let me = data.downcast_mut::<Func>().unwrap();
+ // SAFETY: The caller of TypeErased::run ensures the lifetime
+ // is correct
+ let data = unsafe { &*addr_of!(*data) };
+
+ let me = data
+ .downcast_ref::<Func>()
+ .expect("Function downcast failed");
+
+ // SAFETY: The caller of TypeErased::run ensures the lifetime
+ // is correct
+ let world_data = unsafe {
+ &*(world_data as *const WorldData)
+ };
me.run(world_data);
}),
@@ -87,8 +95,8 @@ macro_rules! impl_system {
}
fn get_local_component_mut<LocalComponent: Component>(
- &mut self,
- ) -> Option<&mut LocalComponent>
+ &self,
+ ) -> Option<ComponentRefMut<LocalComponent>>
{
panic!("System does not have any local components");
}
@@ -123,9 +131,16 @@ pub struct TypeErased
impl TypeErased
{
- pub fn run(&mut self, world_data: &mut WorldData)
+ /// Runs the system.
+ ///
+ /// # Safety
+ /// `world_data` must live at least as long as the [`World`] the system belongs to.
+ pub unsafe fn run(&self, world_data: &WorldData)
{
- (self.func)(self.data.as_mut(), world_data);
+ // You have to dereference for downcasting to work for some reason
+ let data = &*self.data;
+
+ (self.func)(data, world_data);
}
}
@@ -138,7 +153,7 @@ impl Debug for TypeErased
}
/// Function in [`TypeErased`] used to run the system.
-type TypeErasedFunc = dyn Fn(&mut dyn Any, &mut WorldData);
+type TypeErasedFunc = dyn Fn(&dyn Any, &WorldData);
/// A parameter to a [`System`].
///
@@ -149,11 +164,14 @@ pub unsafe trait Param<'world>
type Input;
type Flags;
- fn initialize<SystemImpl>(system: &mut impl System<SystemImpl>, input: Self::Input);
+ fn initialize<SystemImpl>(
+ system: &mut impl System<'world, SystemImpl>,
+ input: Self::Input,
+ );
fn new<SystemImpl>(
- system: &'world mut impl System<SystemImpl>,
- world_data: &'world mut WorldData,
+ system: &'world impl System<'world, SystemImpl>,
+ world_data: &'world WorldData,
) -> Self;
fn is_compatible<Other: Param<'world>>() -> bool;
@@ -172,3 +190,35 @@ where
{
type Tuple = Tup::With;
}
+
+#[derive(Debug)]
+pub struct ComponentRefMut<'a, ComponentT: Component>
+{
+ inner: RefMut<'a, ComponentT>,
+}
+
+impl<'a, ComponentT: Component> ComponentRefMut<'a, ComponentT>
+{
+ pub(crate) fn new(inner: RefMut<'a, ComponentT>) -> Self
+ {
+ Self { inner }
+ }
+}
+
+impl<'a, ComponentT: Component> Deref for ComponentRefMut<'a, ComponentT>
+{
+ type Target = ComponentT;
+
+ fn deref(&self) -> &Self::Target
+ {
+ &self.inner
+ }
+}
+
+impl<'a, ComponentT: Component> DerefMut for ComponentRefMut<'a, ComponentT>
+{
+ fn deref_mut(&mut self) -> &mut Self::Target
+ {
+ &mut self.inner
+ }
+}