use std::any::Any; 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> { /// Adds a spawning a new entity to the action queue. pub fn spawn(&mut self, components: Comps) { self.action_queue.push(Action::Spawn(components.into_vec())); } /// Adds component(s) to a entity. 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())); } /// Removes component(s) from a entity. 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())); } /// Adds stopping the loop in [`Engine::event_loop`] at the next opportune time to the /// action queue. 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) } fn is_compatible>() -> bool { let other_comparable = Other::get_comparable(); other_comparable.downcast_ref::().is_none() } fn get_comparable() -> Box { Box::new(()) } } #[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 { Spawn(Vec>), AddComponents(Uid, Vec>), RemoveComponents(Uid, Vec), Stop, } struct Comparable;