summaryrefslogtreecommitdiff
path: root/ecs/src/lib.rs
diff options
context:
space:
mode:
authorHampusM <hampus@hampusmat.com>2024-03-29 14:20:21 +0100
committerHampusM <hampus@hampusmat.com>2024-03-29 14:20:21 +0100
commit61dfcf1ba2049bf0375821652e49b0e4c4147623 (patch)
tree3eaa2624523c893cb12b08595c4dd9e5250728c4 /ecs/src/lib.rs
parent96ba84e42c77147d297b358c944a48fee3785ae1 (diff)
feat(ecs): make World unwind safe
Diffstat (limited to 'ecs/src/lib.rs')
-rw-r--r--ecs/src/lib.rs94
1 files changed, 80 insertions, 14 deletions
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<RefCell<Box<dyn Component>>>,
+ components: Vec<EntityComponent>,
+}
+
+#[derive(Debug)]
+struct EntityComponent
+{
+ component: Lock<Box<dyn Component>>,
}
#[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<EventId, Vec<usize>>,
- component_storage: RefCell<ComponentStorage>,
- action_queue: RefCell<Vec<Action>>,
+ component_storage: Lock<ComponentStorage>,
+ action_queue: Lock<ActionQueue>,
+}
+
+#[derive(Debug, Default)]
+struct ActionQueue
+{
+ queue: Vec<Action>,
+}
+
+impl ActionQueue
+{
+ fn push(&mut self, action: Action)
+ {
+ self.queue.push(action);
+ }
+
+ fn drain(&mut self, range: impl RangeBounds<usize>) -> Drain<Action>
+ {
+ self.queue.drain(range)
+ }
+}
+
+impl TypeName for ActionQueue
+{
+ fn type_name(&self) -> &'static str
+ {
+ type_name::<Self>()
+ }
}
#[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<Comps>,
}
@@ -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::<HashSet<_>>();
if component_type_ids
@@ -302,3 +360,11 @@ pub struct ComponentStorage
{
entities: Vec<Entity>,
}
+
+impl TypeName for ComponentStorage
+{
+ fn type_name(&self) -> &'static str
+ {
+ type_name::<Self>()
+ }
+}