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 | |
| parent | 251beb34720d2e7d60ceaddc811a65f52f15bdbd (diff) | |
feat(ecs): make components internally mutable
Diffstat (limited to 'ecs')
| -rw-r--r-- | ecs/examples/multiple_queries.rs | 10 | ||||
| -rw-r--r-- | ecs/src/actions.rs | 12 | ||||
| -rw-r--r-- | ecs/src/component.rs | 97 | ||||
| -rw-r--r-- | ecs/src/lib.rs | 160 | ||||
| -rw-r--r-- | ecs/src/system.rs | 104 | ||||
| -rw-r--r-- | ecs/src/system/stateful.rs | 59 | 
6 files changed, 208 insertions, 234 deletions
diff --git a/ecs/examples/multiple_queries.rs b/ecs/examples/multiple_queries.rs index ed02a69..e914cc6 100644 --- a/ecs/examples/multiple_queries.rs +++ b/ecs/examples/multiple_queries.rs @@ -32,18 +32,18 @@ impl Display for EnemyName  fn do_attacks(      attacker_query: Query<(AttackStrength,)>, -    mut enemy_query: Query<(Health, EnemyName)>, +    enemy_query: Query<(Health, EnemyName)>,  )  {      for (attack_strength,) in &attacker_query { -        for (health, enemy_name) in enemy_query.iter_mut() { -            let damage = match attack_strength { +        for (mut health, enemy_name) in &enemy_query { +            let damage = match *attack_strength {                  AttackStrength::Strong => 20,                  AttackStrength::Weak => 10,              };              if health.health <= damage { -                println!("Enemy '{enemy_name}' died"); +                println!("Enemy '{}' died", *enemy_name);                  health.health = 0; @@ -52,7 +52,7 @@ fn do_attacks(              health.health -= damage; -            println!("Enemy '{enemy_name}' took {damage} damage"); +            println!("Enemy '{}' took {damage} damage", *enemy_name);          }      }  } diff --git a/ecs/src/actions.rs b/ecs/src/actions.rs index d67f895..edfee55 100644 --- a/ecs/src/actions.rs +++ b/ecs/src/actions.rs @@ -9,7 +9,7 @@ use crate::WorldData;  #[derive(Debug)]  pub struct Actions<'world>  { -    world_data: &'world mut WorldData, +    world_data: &'world WorldData,  }  impl<'world> Actions<'world> @@ -19,6 +19,7 @@ impl<'world> Actions<'world>      {          self.world_data              .action_queue +            .borrow_mut()              .push(Action::Spawn(components.into_vec()));      }  } @@ -28,13 +29,16 @@ unsafe impl<'world> SystemParam<'world> for Actions<'world>      type Flags = NoInitParamFlag;      type Input = TupleFilterExclude; -    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      {          Self { world_data } diff --git a/ecs/src/component.rs b/ecs/src/component.rs index 7a997c5..07701c8 100644 --- a/ecs/src/component.rs +++ b/ecs/src/component.rs @@ -1,10 +1,16 @@  use std::any::{Any, TypeId}; +use std::cell::{RefCell, RefMut};  use std::fmt::Debug;  use std::ops::{Deref, DerefMut};  use seq_macro::seq; -use crate::system::{Input as SystemInput, Param as SystemParam, System}; +use crate::system::{ +    ComponentRefMut, +    Input as SystemInput, +    Param as SystemParam, +    System, +};  use crate::WorldData;  pub trait Component: SystemInput + Any @@ -49,35 +55,27 @@ pub trait Sequence      where          Self: 'component; -    type MutRefs<'component> -    where -        Self: 'component; -      fn into_vec(self) -> Vec<Box<dyn Component>>;      fn type_ids() -> Vec<TypeId>; -    fn from_components(components: &[Box<dyn Component>]) -> Self::Refs<'_>; - -    fn from_components_mut(components: &mut [Box<dyn Component>]) -> Self::MutRefs<'_>; +    fn from_components(components: &[RefCell<Box<dyn Component>>]) -> Self::Refs<'_>;  }  macro_rules! inner {      ($c: tt) => {          seq!(I in 0..=$c {              impl<#(Comp~I: Component,)*> Sequence for (#(Comp~I,)*) { -                type Refs<'component> = (#(&'component Comp~I,)*) +                type Refs<'component> = (#(ComponentRefMut<'component, Comp~I>,)*)                      where Self: 'component; -                type MutRefs<'component> = (#(&'component mut Comp~I,)*) -                    where Self: 'component; - - -                fn into_vec(self) -> Vec<Box<dyn Component>> { +                fn into_vec(self) -> Vec<Box<dyn Component>> +                {                      Vec::from_iter([#(Box::new(self.I) as Box<dyn Component>,)*])                  } -                fn type_ids() -> Vec<TypeId> { +                fn type_ids() -> Vec<TypeId> +                {                      vec![                          #(                              TypeId::of::<Comp~I>(), @@ -85,46 +83,34 @@ macro_rules! inner {                      ]                  } -                fn from_components(components: &[Box<dyn Component>]) -> Self::Refs<'_> +                fn from_components( +                    components: &[RefCell<Box<dyn Component>>] +                ) -> Self::Refs<'_>                  {                      #( -                        let mut comp_~I = None; +                        let mut comp_~I: Option<RefMut<Box<dyn Component>>> = None;                      )*                      for comp in components { -                        #( -                            if comp.is::<Comp~I>() { -                                comp_~I = Some(comp); -                                continue; -                            } -                        )* -                    } - -                    (#( -                        comp_~I.unwrap().downcast_ref::<Comp~I>().unwrap(), -                    )*) - -                } - -                fn from_components_mut( -                    components: &mut [Box<dyn Component>], -                ) -> Self::MutRefs<'_> -                { -                    #( -                        let mut comp_~I = None; -                    )* +                        let Ok(comp_ref) = comp.try_borrow_mut() else { +                            continue; +                        }; -                    for comp in components.iter_mut() {                          #( -                            if comp.is::<Comp~I>() { -                                comp_~I = Some(comp); +                            if comp_ref.is::<Comp~I>() { +                                comp_~I = Some(comp_ref);                                  continue;                              }                          )*                      }                      (#( -                        comp_~I.unwrap().downcast_mut::<Comp~I>().unwrap(), +                        ComponentRefMut::new( +                            RefMut::filter_map( +                                comp_~I.unwrap(), +                                |component| component.downcast_mut::<Comp~I>() +                            ).expect("Failed to downcast component") +                        ),                      )*)                  }              } @@ -140,17 +126,7 @@ seq!(C in 0..=64 {  #[derive(Debug)]  pub struct Local<'world, LocalComponent: Component>  { -    local_component: &'world mut LocalComponent, -} - -impl<'world, LocalComponent> Local<'world, LocalComponent> -where -    LocalComponent: Component, -{ -    fn new(local_component: &'world mut LocalComponent) -> Self -    { -        Self { local_component } -    } +    local_component: ComponentRefMut<'world, LocalComponent>,  }  unsafe impl<'world, LocalComponent> SystemParam<'world> for Local<'world, LocalComponent> @@ -160,21 +136,24 @@ where      type Flags = ();      type Input = LocalComponent; -    fn initialize<SystemImpl>(system: &mut impl System<SystemImpl>, input: Self::Input) +    fn initialize<SystemImpl>( +        system: &mut impl System<'world, SystemImpl>, +        input: Self::Input, +    )      {          system.set_local_component(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      {          let local_component = system              .get_local_component_mut::<LocalComponent>()              .expect("Local component is uninitialized"); -        Self::new(local_component) +        Self { local_component }      }      fn is_compatible<Other: SystemParam<'world>>() -> bool @@ -202,7 +181,7 @@ where      fn deref(&self) -> &Self::Target      { -        self.local_component +        &self.local_component      }  } @@ -212,6 +191,6 @@ where  {      fn deref_mut(&mut self) -> &mut Self::Target      { -        self.local_component +        &mut self.local_component      }  } diff --git a/ecs/src/lib.rs b/ecs/src/lib.rs index 6b9373c..d781b3e 100644 --- a/ecs/src/lib.rs +++ b/ecs/src/lib.rs @@ -1,10 +1,11 @@  #![deny(clippy::all, clippy::pedantic)]  use std::any::{Any, TypeId}; +use std::cell::RefCell;  use std::collections::{HashMap, HashSet};  use std::fmt::Debug;  use std::marker::PhantomData; -use std::slice::{Iter as SliceIter, IterMut as SliceIterMut}; +use std::slice::Iter as SliceIter;  use crate::actions::Action;  use crate::component::{Component, Sequence as ComponentSequence}; @@ -28,7 +29,7 @@ pub use ecs_macros::Component;  #[derive(Debug, Default)]  struct Entity  { -    components: Vec<Box<dyn Component>>, +    components: Vec<RefCell<Box<dyn Component>>>,  }  #[derive(Debug, Default)] @@ -50,18 +51,20 @@ impl World      where          Comps: ComponentSequence,      { -        self.data -            .component_storage -            .entities -            .push(Entity { components: components.into_vec() }); +        self.data.component_storage.entities.push(Entity { +            components: components +                .into_vec() +                .into_iter() +                .map(RefCell::new) +                .collect(), +        });      } -    pub fn register_system<TSystem, SystemImpl>( -        &mut self, +    pub fn register_system<'this, SystemImpl>( +        &'this mut self,          event: &impl Event, -        system: TSystem, -    ) where -        TSystem: System<SystemImpl>, +        system: impl System<'this, SystemImpl>, +    )      {          self.systems.push(system.into_type_erased()); @@ -77,36 +80,38 @@ impl World      ///      /// # Panics      /// Will panic if a system has dissapeared. -    pub fn emit(&mut self, event: &impl Event) +    pub fn emit(&self, event: &impl Event)      {          let Some(system_indices) = self.data.events.get(&event.id()).cloned() else {              return;          };          for system_index in system_indices { -            let system = self.systems.get_mut(system_index).unwrap(); +            let system = self.systems.get(system_index).unwrap(); -            system.run(&mut self.data); +            // SAFETY: The world data lives long enough +            unsafe { +                system.run(&self.data); +            }          }      } -    pub fn query<Comps>(&mut self) -> Query<Comps> +    pub fn query<Comps>(&self) -> Query<Comps>      where          Comps: ComponentSequence,      { -        Query::new(&mut self.data) +        Query::new(&self.data)      }      /// Peforms the actions that have been queued up using [`Actions`].      pub fn perform_queued_actions(&mut self)      { -        for action in self.data.action_queue.drain(..) { +        for action in self.data.action_queue.borrow_mut().drain(..) {              match action {                  Action::Spawn(components) => { -                    self.data -                        .component_storage -                        .entities -                        .push(Entity { components }); +                    self.data.component_storage.entities.push(Entity { +                        components: components.into_iter().map(RefCell::new).collect(), +                    });                  }              }          } @@ -118,7 +123,7 @@ pub struct WorldData  {      events: HashMap<EventId, Vec<usize>>,      component_storage: ComponentStorage, -    action_queue: Vec<Action>, +    action_queue: RefCell<Vec<Action>>,  }  #[derive(Debug)] @@ -126,7 +131,7 @@ pub struct Query<'world, Comps>  where      Comps: ComponentSequence,  { -    world_data: &'world mut WorldData, +    world_data: &'world WorldData,      comps_pd: PhantomData<Comps>,  } @@ -134,17 +139,7 @@ impl<'world, Comps> Query<'world, Comps>  where      Comps: ComponentSequence,  { -    fn new(world_data: &'world mut WorldData) -> Self -    { -        Self { world_data, comps_pd: PhantomData } -    } -} - -impl<'world, Comps> Query<'world, Comps> -where -    Comps: ComponentSequence, -{ -    pub fn iter(&self) -> QueryComponentIter<Comps> +    pub fn iter(&self) -> QueryComponentIter<'world, Comps>      {          QueryComponentIter {              entity_iter: self.world_data.component_storage.entities.iter(), @@ -153,13 +148,9 @@ where          }      } -    pub fn iter_mut(&mut self) -> QueryComponentMutIter<Comps> +    fn new(world_data: &'world WorldData) -> Self      { -        QueryComponentMutIter { -            entity_iter: self.world_data.component_storage.entities.iter_mut(), -            component_type_ids: Comps::type_ids(), -            comps_pd: PhantomData, -        } +        Self { world_data, comps_pd: PhantomData }      }  } @@ -176,19 +167,6 @@ where      }  } -impl<'world, Comps> IntoIterator for &'world mut Query<'world, Comps> -where -    Comps: ComponentSequence, -{ -    type IntoIter = QueryComponentMutIter<'world, Comps>; -    type Item = Comps::MutRefs<'world>; - -    fn into_iter(self) -> Self::IntoIter -    { -        self.iter_mut() -    } -} -  unsafe impl<'world, Comps> SystemParam<'world> for Query<'world, Comps>  where      Comps: ComponentSequence, @@ -196,13 +174,16 @@ where      type Flags = NoInitSystemParamFlag;      type Input = TupleFilterExclude; -    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      {          Self::new(world_data) @@ -268,75 +249,26 @@ where      fn next(&mut self) -> Option<Self::Item>      { -        let matching_entity = find_entity_with_components::<&Entity>( -            &mut self.entity_iter, -            &self.component_type_ids, -        )?; +        let matching_entity = +            find_entity_with_components(&mut self.entity_iter, &self.component_type_ids)?;          Some(Comps::from_components(&matching_entity.components))      }  } -pub struct QueryComponentMutIter<'world, Comps> -{ -    entity_iter: SliceIterMut<'world, Entity>, -    component_type_ids: Vec<TypeId>, -    comps_pd: PhantomData<Comps>, -} - -impl<'world, Comps> Iterator for QueryComponentMutIter<'world, Comps> -where -    Comps: ComponentSequence + 'world, -{ -    type Item = Comps::MutRefs<'world>; - -    fn next(&mut self) -> Option<Self::Item> -    { -        let matching_entity = find_entity_with_components::<&mut Entity>( -            &mut self.entity_iter, -            &self.component_type_ids, -        )?; - -        Some(Comps::from_components_mut(&mut matching_entity.components)) -    } -} - -trait EntityRef -{ -    fn components(&self) -> &[Box<dyn Component>]; -} - -impl EntityRef for &Entity -{ -    fn components(&self) -> &[Box<dyn Component>] -    { -        &self.components -    } -} - -impl EntityRef for &mut Entity -{ -    fn components(&self) -> &[Box<dyn Component>] -    { -        &self.components -    } -} - -fn find_entity_with_components<EntityRefT>( -    entity_iter: &mut impl Iterator<Item = EntityRefT>, +fn find_entity_with_components<'world>( +    entity_iter: &mut impl Iterator<Item = &'world Entity>,      component_type_ids: &[TypeId], -) -> Option<EntityRefT> -where -    EntityRefT: EntityRef, +) -> Option<&'world Entity>  {      // TODO: This is a really dumb and slow way to do this. Refactor the world      // to store components in archetypes      entity_iter.find(|entity| { -        let entity_components: HashSet<_> = entity -            .components() +        let entity_components = entity +            .components              .iter() -            .map(|component| component.as_ref().type_id()) -            .collect(); +            .filter_map(|component| Some(component.try_borrow().ok()?.as_ref().type_id())) +            .collect::<HashSet<_>>();          if component_type_ids              .iter() 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 +    } +} diff --git a/ecs/src/system/stateful.rs b/ecs/src/system/stateful.rs index 3f71000..7ce87fa 100644 --- a/ecs/src/system/stateful.rs +++ b/ecs/src/system/stateful.rs @@ -1,12 +1,12 @@ -use std::any::{type_name, TypeId}; +use std::any::{type_name, Any, TypeId}; +use std::cell::{RefCell, RefMut};  use std::collections::HashMap; -use std::ptr::addr_of_mut;  use seq_macro::seq;  use crate::component::Component;  use crate::system::util::check_params_are_compatible; -use crate::system::{Into as IntoSystem, Param, System, TypeErased}; +use crate::system::{ComponentRefMut, Into as IntoSystem, Param, System, TypeErased};  use crate::tuple::{      Filter as TupleFilter,      FilterExclude as TupleFilterExclude, @@ -20,13 +20,13 @@ use crate::WorldData;  pub struct Stateful<Func>  {      func: Func, -    local_components: HashMap<TypeId, Box<dyn Component>>, +    local_components: HashMap<TypeId, RefCell<Box<dyn Component>>>,  }  macro_rules! impl_system {      ($c: tt) => {          seq!(I in 0..$c { -            impl<'world, Func, #(TParam~I,)*> System<fn(&'world (), #(TParam~I,)*)> +            impl<'world, Func, #(TParam~I,)*> System<'world, fn(&'world (), #(TParam~I,)*)>                  for Stateful<Func>              where                  Func: Fn(#(TParam~I,)*) + Copy + 'static, @@ -76,7 +76,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); @@ -85,17 +87,7 @@ macro_rules! impl_system {                      let func = self.func;                      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)                      },)*);                  } @@ -104,7 +96,17 @@ macro_rules! impl_system {                      TypeErased {                          data: Box::new(self),                          func: Box::new(|data, world_data| { -                            let me = data.downcast_mut::<Self>().unwrap(); +                            // SAFETY: The caller of TypeErased::run ensures the lifetime +                            // is correct +                            let data = unsafe { &*(data as *const dyn Any) }; + +                            let me = data.downcast_ref::<Self>().unwrap(); + +                            // SAFETY: The caller of TypeErased::run ensures the lifetime +                            // is correct +                            let world_data = unsafe { +                                &*(world_data as *const WorldData) +                            };                              me.run(world_data);                          }), @@ -112,12 +114,17 @@ macro_rules! impl_system {                  }                  fn get_local_component_mut<LocalComponent: Component>( -                    &mut self, -                ) -> Option<&mut LocalComponent> +                    &self, +                ) -> Option<ComponentRefMut<LocalComponent>>                  { -                    self.local_components -                        .get_mut(&TypeId::of::<LocalComponent>())? -                        .downcast_mut() +                    let local_component = self.local_components +                        .get(&TypeId::of::<LocalComponent>())? +                        .borrow_mut(); + +                    Some(ComponentRefMut::new(RefMut::filter_map( +                        local_component, +                        |local_component| local_component.downcast_mut() +                    ).ok()?))                  }                  fn set_local_component<LocalComponent: Component>( @@ -126,8 +133,10 @@ macro_rules! impl_system {                  )                  {                      self.local_components -                        .insert(TypeId::of::<LocalComponent>(), -                        Box::new(local_component)); +                        .insert( +                            TypeId::of::<LocalComponent>(), +                            RefCell::new(Box::new(local_component)) +                        );                  }              }  | 
