use std::marker::PhantomData; use std::sync::{Arc, Weak}; use crate::component::{ Component, Metadata as ComponentMetadata, Sequence as ComponentSequence, }; use crate::system::{NoInitParamFlag, Param as SystemParam, System}; use crate::uid::{Kind as UidKind, Uid}; use crate::{ActionQueue, World}; /// Used to to queue up actions for a [`World`] to perform. #[derive(Debug)] pub struct Actions<'world> { action_queue: &'world ActionQueue, action_queue_weak: Weak, } impl<'world> Actions<'world> { /// Queues up a entity to spawn at the end of the current tick. pub fn spawn(&mut self, components: Comps) { self.action_queue.push(Action::Spawn( components.into_vec(), EventIds { ids: Comps::added_event_ids() }, )); } /// Queues up adding component(s) to a entity at the end of the current tick. pub fn add_components(&mut self, entity_uid: Uid, components: Comps) where Comps: ComponentSequence, { debug_assert_eq!(entity_uid.kind(), UidKind::Entity); self.action_queue.push(Action::AddComponents( entity_uid, components.into_vec(), EventIds { ids: Comps::added_event_ids() }, )); } /// Queues up removing component(s) from a entity at the end of the current tick. pub fn remove_components(&mut self, entity_uid: Uid) where Comps: ComponentSequence, { debug_assert_eq!(entity_uid.kind(), UidKind::Entity); self.action_queue.push(Action::RemoveComponents( entity_uid, Comps::metadata(), EventIds { ids: Comps::removed_event_ids() }, )); } /// Stops the [`World`]. The world will finish the current tick and that tick will be /// the last. pub fn stop(&mut self) { 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_weak: Arc::downgrade(action_queue), } } } unsafe impl<'world> SystemParam<'world> for Actions<'world> { type Flags = NoInitParamFlag; type Input = (); fn initialize( _system: &mut impl System<'world, SystemImpl>, _input: Self::Input, ) { } fn new( _system: &'world impl System<'world, SystemImpl>, world: &'world World, ) -> Self { Self::new(&world.data.action_queue) } } #[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) } } #[derive(Debug)] pub(crate) struct EventIds { pub(crate) ids: Vec, } /// A action for a [`System`] to perform. #[derive(Debug)] pub(crate) enum Action { Spawn(Vec>, EventIds), AddComponents(Uid, Vec>, EventIds), RemoveComponents(Uid, Vec, EventIds), Stop, }