diff options
Diffstat (limited to 'engine-ecs/src/sole.rs')
| -rw-r--r-- | engine-ecs/src/sole.rs | 104 |
1 files changed, 104 insertions, 0 deletions
diff --git a/engine-ecs/src/sole.rs b/engine-ecs/src/sole.rs new file mode 100644 index 0000000..82e5e0f --- /dev/null +++ b/engine-ecs/src/sole.rs @@ -0,0 +1,104 @@ +use std::any::{Any, type_name}; +use std::fmt::Debug; +use std::marker::PhantomData; +use std::ops::{Deref, DerefMut}; +use std::sync::Arc; + +use crate::World; +use crate::lock::{Lock, WriteGuard}; +use crate::system::{Metadata as SystemMetadata, Param as SystemParam}; + +/// A type which has a single instance and is shared globally. +pub trait Sole: Any +{ + 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<Real: 'static>(&mut self) -> Option<&mut Real> + { + self.as_any_mut().downcast_mut() + } + + pub fn downcast_ref<Real: 'static>(&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() + } +} + +/// Holds a reference to a globally shared singleton value. +#[derive(Debug)] +pub struct Single<'world, SoleT: Sole> +{ + sole: WriteGuard<'world, Box<dyn Sole>>, + _ph: PhantomData<SoleT>, +} + +impl<'world, SoleT> Single<'world, SoleT> +where + SoleT: Sole, +{ + pub(crate) fn new(sole: &'world Arc<Lock<Box<dyn Sole>>>) -> Self + { + Self { + sole: sole.write_nonblock().unwrap_or_else(|_| { + panic!( + "Failed to aquire read-write lock to single component {}", + type_name::<SoleT>() + ) + }), + _ph: PhantomData, + } + } +} + +impl<'world, SoleT> SystemParam<'world> for Single<'world, SoleT> +where + SoleT: Sole, +{ + type Input = (); + + fn new(world: &'world World, _system_metadata: &SystemMetadata) -> Self + { + let sole = world.data.sole_storage.get::<SoleT>().unwrap_or_else(|| { + panic!("Sole {} was not found in world", type_name::<SoleT>()) + }); + + Self::new(sole) + } +} + +impl<SoleT> Deref for Single<'_, SoleT> +where + SoleT: Sole, +{ + type Target = SoleT; + + fn deref(&self) -> &Self::Target + { + self.sole.downcast_ref().unwrap() + } +} + +impl<SoleT> DerefMut for Single<'_, SoleT> +where + SoleT: Sole, +{ + fn deref_mut(&mut self) -> &mut Self::Target + { + self.sole.downcast_mut().unwrap() + } +} |
