From c0fbe4b3790c771836b1723a81a2290d9796f429 Mon Sep 17 00:00:00 2001 From: HampusM Date: Sat, 6 Apr 2024 16:30:58 +0200 Subject: feat(ecs): add weak reference actions --- ecs/src/actions.rs | 90 ++++++++++++++++++++++++++++++++++++++++++------------ ecs/src/lib.rs | 2 +- 2 files changed, 71 insertions(+), 21 deletions(-) (limited to 'ecs/src') diff --git a/ecs/src/actions.rs b/ecs/src/actions.rs index a5aaf0c..cc27f09 100644 --- a/ecs/src/actions.rs +++ b/ecs/src/actions.rs @@ -1,44 +1,55 @@ use std::any::Any; +use std::marker::PhantomData; +use std::sync::{Arc, Weak}; use crate::component::{Component, Sequence as ComponentSequence}; +use crate::lock::{Lock, WriteGuard}; use crate::system::{NoInitParamFlag, Param as SystemParam, System}; use crate::tuple::FilterExclude as TupleFilterExclude; -use crate::WorldData; +use crate::{ActionQueue, WorldData}; /// Used to to queue up actions for a [`World`] to perform. #[derive(Debug)] pub struct Actions<'world> { - world_data: &'world WorldData, + action_queue: WriteGuard<'world, ActionQueue>, + action_queue_weak: Weak>, } impl<'world> Actions<'world> { /// Adds a spawning a new entity to the action queue. - /// - /// # Panics - /// Will panic if a mutable internal lock cannot be acquired. pub fn spawn(&mut self, components: Comps) { - self.world_data - .action_queue - .write_nonblock() - .expect("Failed to aquire read-write action queue lock") - .push(Action::Spawn(components.into_vec())); + self.action_queue.push(Action::Spawn(components.into_vec())); } - /// Adds stopping the loop in [`Engine::event_loop`] at the next oppertune time to the + /// Adds stopping the loop in [`Engine::event_loop`] at the next opportune time to the /// action queue. - /// - /// # Panics - /// Will panic if a mutable internal lock cannot be acquired. pub fn stop(&mut self) { - self.world_data - .action_queue - .write_nonblock() - .expect("Failed to aquire read-write action queue lock") - .push(Action::Stop); + self.action_queue.push(Action::Stop); + } + + /// Returns a struct which holds a weak reference to the [`World`] that `Actions` + /// references and that can be used to aquire a new `Actions` instance if the + /// referenced [`World`] is still alive. + #[must_use] + pub fn to_weak_ref(&self) -> WeakRef + { + WeakRef { + action_queue: self.action_queue_weak.clone(), + } + } + + fn new(action_queue: &'world Arc>) -> Self + { + Self { + action_queue: action_queue + .write_nonblock() + .expect("Failed to aquire read-write action queue lock"), + action_queue_weak: Arc::downgrade(action_queue), + } } } @@ -59,7 +70,7 @@ unsafe impl<'world> SystemParam<'world> for Actions<'world> world_data: &'world WorldData, ) -> Self { - Self { world_data } + Self::new(&world_data.action_queue) } fn is_compatible>() -> bool @@ -75,6 +86,45 @@ unsafe impl<'world> SystemParam<'world> for Actions<'world> } } +#[derive(Debug, Clone)] +pub struct WeakRef +{ + action_queue: Weak>, +} + +impl WeakRef +{ + /// Returns a struct which can be used to retrieve a [`Actions`]. + /// + /// Returns [`None`] if the referenced [`World`] has been dropped. + #[must_use] + pub fn access(&self) -> Option> + { + Some(Ref { + action_queue: self.action_queue.upgrade()?, + _pd: PhantomData, + }) + } +} + +/// Intermediate between [`Actions`] and [`WeakRef`]. Contains a strong reference to +/// a world which is not allowed direct access to. +#[derive(Debug, Clone)] +pub struct Ref<'weak_ref> +{ + action_queue: Arc>, + _pd: PhantomData<&'weak_ref ()>, +} + +impl<'weak_ref> Ref<'weak_ref> +{ + #[must_use] + pub fn to_actions(&self) -> Actions<'_> + { + Actions::new(&self.action_queue) + } +} + /// A action for a [`System`] to perform. #[derive(Debug)] pub(crate) enum Action diff --git a/ecs/src/lib.rs b/ecs/src/lib.rs index 1c4e44f..a2fc36e 100644 --- a/ecs/src/lib.rs +++ b/ecs/src/lib.rs @@ -211,7 +211,7 @@ pub struct WorldData { events: HashMap>, component_storage: Arc>, - action_queue: Lock, + action_queue: Arc>, } #[derive(Debug, Default)] -- cgit v1.2.3-18-g5258