use std::any::{type_name, Any, TypeId}; use std::fmt::Debug; use std::marker::PhantomData; use std::ops::{Deref, DerefMut}; use std::sync::{Arc, Weak}; use crate::lock::{Lock, WriteGuard}; use crate::system::{NoInitParamFlag, Param as SystemParam, System}; use crate::type_name::TypeName; use crate::World; /// A type which has a single instance and is shared globally. pub trait Sole: Any + TypeName { fn drop_last(&self) -> bool; fn as_any_mut(&mut self) -> &mut dyn Any; fn as_any(&self) -> &dyn Any; } impl dyn Sole { pub fn downcast_mut(&mut self) -> Option<&mut Real> { self.as_any_mut().downcast_mut() } pub fn downcast_ref(&self) -> Option<&Real> { self.as_any().downcast_ref() } } impl Debug for dyn Sole { fn fmt(&self, formatter: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { formatter.debug_struct("Sole").finish_non_exhaustive() } } impl TypeName for Box { fn type_name(&self) -> &'static str { self.as_ref().type_name() } } /// Holds a reference to a globally shared singleton value. #[derive(Debug)] pub struct Single<'world, SoleT: Sole> { sole: WriteGuard<'world, Box>, sole_weak: Weak>>, _ph: PhantomData, } impl<'world, SoleT> Single<'world, SoleT> where SoleT: Sole, { /// Returns a struct which holds a weak reference to the [`World`] that `Single` /// references and that can be used to aquire a new `Single` if the referenced /// [`World`] is still alive. #[must_use] pub fn to_weak_ref(&self) -> SingleWeakRef { SingleWeakRef { sole: self.sole_weak.clone(), _ph: PhantomData, } } fn new(sole: &'world Arc>>) -> Self { Self { sole: sole.write_nonblock().unwrap_or_else(|_| { panic!( "Failed to aquire read-write lock to single component {}", type_name::() ) }), sole_weak: Arc::downgrade(sole), _ph: PhantomData, } } } unsafe impl<'world, SoleT> SystemParam<'world> for Single<'world, SoleT> where SoleT: Sole, { 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 { let sole = world.data.sole_storage.get::().unwrap_or_else(|| { panic!("Sole {} was not found in world", type_name::()) }); Self::new(sole) } fn is_compatible>() -> bool { let other_comparable = Other::get_comparable(); let Some(comparable) = other_comparable.downcast_ref::() else { // The other system param is not Single return true; }; TypeId::of::() != comparable.sole_type_id } fn get_comparable() -> Box { Box::new(Comparable { sole_type_id: TypeId::of::() }) } } impl<'world, SoleT> Deref for Single<'world, SoleT> where SoleT: Sole, { type Target = SoleT; fn deref(&self) -> &Self::Target { self.sole.downcast_ref().unwrap() } } impl<'world, SoleT> DerefMut for Single<'world, SoleT> where SoleT: Sole, { fn deref_mut(&mut self) -> &mut Self::Target { self.sole.downcast_mut().unwrap() } } #[derive(Debug, Clone)] pub struct SingleWeakRef where SoleT: Sole, { sole: Weak>>, _ph: PhantomData, } impl SingleWeakRef where SoleT: Sole, { /// Returns a struct which can be used to retrieve a [`Single`]. /// /// Returns [`None`] if the referenced [`World`] has been dropped. #[must_use] pub fn access(&self) -> Option> { Some(SingleRef { sole: self.sole.upgrade()?, _pd: PhantomData, }) } } /// Intermediate between [`Single`] and [`SingleWeakRef`]. Contains a strong reference to /// a world which is not allowed direct access to. #[derive(Debug, Clone)] pub struct SingleRef<'weak_ref, SoleT> where SoleT: Sole, { sole: Arc>>, _pd: PhantomData<&'weak_ref SoleT>, } impl<'weak_ref, SoleT> SingleRef<'weak_ref, SoleT> where SoleT: Sole, { #[must_use] pub fn to_single(&self) -> Single<'_, SoleT> { Single::new(&self.sole) } } struct Comparable { sole_type_id: TypeId, }