summaryrefslogtreecommitdiff
path: root/ecs
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
parent251beb34720d2e7d60ceaddc811a65f52f15bdbd (diff)
feat(ecs): make components internally mutable
Diffstat (limited to 'ecs')
-rw-r--r--ecs/examples/multiple_queries.rs10
-rw-r--r--ecs/src/actions.rs12
-rw-r--r--ecs/src/component.rs97
-rw-r--r--ecs/src/lib.rs160
-rw-r--r--ecs/src/system.rs104
-rw-r--r--ecs/src/system/stateful.rs59
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))
+ );
}
}