From 61dfcf1ba2049bf0375821652e49b0e4c4147623 Mon Sep 17 00:00:00 2001 From: HampusM Date: Fri, 29 Mar 2024 14:20:21 +0100 Subject: feat(ecs): make World unwind safe --- ecs/src/lib.rs | 94 +++++++++++++++++++++++++++++++++++++++++++++++++--------- 1 file changed, 80 insertions(+), 14 deletions(-) (limited to 'ecs/src/lib.rs') diff --git a/ecs/src/lib.rs b/ecs/src/lib.rs index 18e7381..11e67f7 100644 --- a/ecs/src/lib.rs +++ b/ecs/src/lib.rs @@ -1,15 +1,17 @@ #![deny(clippy::all, clippy::pedantic)] -use std::any::{Any, TypeId}; -use std::cell::{Ref, RefCell}; +use std::any::{type_name, Any, TypeId}; use std::collections::{HashMap, HashSet}; use std::fmt::Debug; use std::marker::PhantomData; +use std::ops::RangeBounds; use std::slice::Iter as SliceIter; +use std::vec::Drain; use crate::actions::Action; use crate::component::{Component, Sequence as ComponentSequence}; use crate::event::{Event, Id as EventId}; +use crate::lock::{Lock, ReadGuard}; use crate::system::{ NoInitParamFlag as NoInitSystemParamFlag, Param as SystemParam, @@ -17,19 +19,28 @@ use crate::system::{ TypeErased as TypeErasedSystem, }; use crate::tuple::FilterExclude as TupleFilterExclude; +use crate::type_name::TypeName; pub mod actions; pub mod component; pub mod event; +pub mod lock; pub mod system; pub mod tuple; +pub mod type_name; pub use ecs_macros::Component; #[derive(Debug, Default)] struct Entity { - components: Vec>>, + components: Vec, +} + +#[derive(Debug)] +struct EntityComponent +{ + component: Lock>, } #[derive(Debug, Default)] @@ -53,13 +64,14 @@ impl World { self.data .component_storage - .borrow_mut() + .write_nonblock() + .expect("Failed to acquire read-write component storage lock") .entities .push(Entity { components: components .into_vec() .into_iter() - .map(RefCell::new) + .map(|component| EntityComponent { component: Lock::new(component) }) .collect(), }); } @@ -110,17 +122,26 @@ impl World /// Peforms the actions that have been queued up using [`Actions`]. pub fn perform_queued_actions(&self) { - for action in self.data.action_queue.borrow_mut().drain(..) { + for action in self + .data + .action_queue + .write_nonblock() + .expect("Failed to aquire read-write action queue lock") + .drain(..) + { match action { Action::Spawn(components) => { self.data .component_storage - .borrow_mut() + .write_nonblock() + .expect("Failed to acquire read-write component storage lock") .entities .push(Entity { components: components .into_iter() - .map(RefCell::new) + .map(|component| EntityComponent { + component: Lock::new(component), + }) .collect(), }); } @@ -133,8 +154,35 @@ impl World pub struct WorldData { events: HashMap>, - component_storage: RefCell, - action_queue: RefCell>, + component_storage: Lock, + action_queue: Lock, +} + +#[derive(Debug, Default)] +struct ActionQueue +{ + queue: Vec, +} + +impl ActionQueue +{ + fn push(&mut self, action: Action) + { + self.queue.push(action); + } + + fn drain(&mut self, range: impl RangeBounds) -> Drain + { + self.queue.drain(range) + } +} + +impl TypeName for ActionQueue +{ + fn type_name(&self) -> &'static str + { + type_name::() + } } #[derive(Debug)] @@ -142,7 +190,7 @@ pub struct Query<'world, Comps> where Comps: ComponentSequence, { - component_storage: Ref<'world, ComponentStorage>, + component_storage: ReadGuard<'world, ComponentStorage>, comps_pd: PhantomData, } @@ -164,7 +212,10 @@ where fn new(world_data: &'world WorldData) -> Self { Self { - component_storage: world_data.component_storage.borrow(), + component_storage: world_data + .component_storage + .read_nonblock() + .expect("Failed to acquire read-only component storage lock"), comps_pd: PhantomData, } } @@ -268,7 +319,12 @@ where let matching_entity = find_entity_with_components(&mut self.entity_iter, &self.component_type_ids)?; - Some(Comps::from_components(&matching_entity.components)) + Some(Comps::from_components( + matching_entity + .components + .iter() + .map(|component| &component.component), + )) } } @@ -283,7 +339,9 @@ fn find_entity_with_components<'world>( let entity_components = entity .components .iter() - .filter_map(|component| Some(component.try_borrow().ok()?.as_ref().type_id())) + .filter_map(|component| { + Some(component.component.read_nonblock().ok()?.as_ref().type_id()) + }) .collect::>(); if component_type_ids @@ -302,3 +360,11 @@ pub struct ComponentStorage { entities: Vec, } + +impl TypeName for ComponentStorage +{ + fn type_name(&self) -> &'static str + { + type_name::() + } +} -- cgit v1.2.3-18-g5258