From ca51244e9d462c661d29dc60ce5bf6f9056c569b Mon Sep 17 00:00:00 2001 From: HampusM Date: Wed, 10 Apr 2024 20:37:53 +0200 Subject: chore(ecs): make shared singletons not components --- ecs/src/sole.rs | 134 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 134 insertions(+) create mode 100644 ecs/src/sole.rs (limited to 'ecs/src/sole.rs') diff --git a/ecs/src/sole.rs b/ecs/src/sole.rs new file mode 100644 index 0000000..e5166e9 --- /dev/null +++ b/ecs/src/sole.rs @@ -0,0 +1,134 @@ +use std::any::{type_name, Any, TypeId}; +use std::fmt::Debug; +use std::marker::PhantomData; +use std::ops::{Deref, DerefMut}; + +use crate::lock::WriteGuard; +use crate::system::{NoInitParamFlag, Param as SystemParam, System}; +use crate::tuple::FilterExclude as TupleFilterExclude; +use crate::type_name::TypeName; +use crate::WorldData; + +/// A type which has a single instance and is shared globally. +pub trait Sole: Any + TypeName +{ + 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>, + _ph: PhantomData, +} + +unsafe impl<'world, SoleT> SystemParam<'world> for Single<'world, SoleT> +where + SoleT: Sole, +{ + type Flags = NoInitParamFlag; + type Input = TupleFilterExclude; + + fn initialize( + _system: &mut impl System<'world, SystemImpl>, + _input: Self::Input, + ) + { + } + + fn new( + _system: &'world impl System<'world, SystemImpl>, + world_data: &'world WorldData, + ) -> Self + { + let sole = world_data + .sole_storage + .get::() + .expect("Sole was not found in world") + .write_nonblock() + .unwrap_or_else(|_| { + panic!( + "Failed to aquire read-write lock to single component {}", + type_name::() + ) + }); + + Self { sole, _ph: PhantomData } + } + + 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() + } +} + +struct Comparable +{ + sole_type_id: TypeId, +} -- cgit v1.2.3-18-g5258