diff options
author | HampusM <hampus@hampusmat.com> | 2024-03-12 20:54:42 +0100 |
---|---|---|
committer | HampusM <hampus@hampusmat.com> | 2024-03-12 20:54:42 +0100 |
commit | 01066718b0f13846587d26b1869f03e3713082c6 (patch) | |
tree | 0ef39b49b26330ab1ed2526105a15c7a0cba7c85 /ecs/src/system.rs | |
parent | 251beb34720d2e7d60ceaddc811a65f52f15bdbd (diff) |
feat(ecs): make components internally mutable
Diffstat (limited to 'ecs/src/system.rs')
-rw-r--r-- | ecs/src/system.rs | 104 |
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 + } +} |