use std::marker::PhantomData; use std::sync::{Arc, Weak}; use crate::component::{Parts as ComponentParts, Sequence as ComponentSequence}; use crate::system::{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_parts_array().into())); } /// Queues up despawning a entity at the end of the current tick. pub fn despawn(&mut self, entity_uid: Uid) { debug_assert_eq!(entity_uid.kind(), UidKind::Entity); self.action_queue.push(Action::Despawn(entity_uid)); } /// 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); if Comps::COUNT == 0 { return; } self.action_queue.push(Action::AddComponents( entity_uid, components.into_parts_array().into(), )); } /// Queues up removing component(s) from a entity at the end of the current tick. pub fn remove_components( &mut self, entity_uid: Uid, component_ids: impl IntoIterator, ) { debug_assert_eq!(entity_uid.kind(), UidKind::Entity); let mut component_ids = component_ids.into_iter().peekable(); if component_ids.peek().is_none() { return; } self.action_queue.push(Action::RemoveComponents( entity_uid, component_ids.collect(), )); } /// 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), } } } impl<'world> SystemParam<'world> for Actions<'world> { 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 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 { Spawn(Vec), Despawn(Uid), AddComponents(Uid, Vec), RemoveComponents(Uid, Vec), Stop, }