summaryrefslogtreecommitdiff
path: root/ecs/src/sole.rs
diff options
context:
space:
mode:
Diffstat (limited to 'ecs/src/sole.rs')
-rw-r--r--ecs/src/sole.rs134
1 files changed, 134 insertions, 0 deletions
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<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()
+ }
+}
+
+impl TypeName for Box<dyn Sole>
+{
+ 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<dyn Sole>>,
+ _ph: PhantomData<SoleT>,
+}
+
+unsafe impl<'world, SoleT> SystemParam<'world> for Single<'world, SoleT>
+where
+ SoleT: Sole,
+{
+ type Flags = NoInitParamFlag;
+ type Input = TupleFilterExclude;
+
+ fn initialize<SystemImpl>(
+ _system: &mut impl System<'world, SystemImpl>,
+ _input: Self::Input,
+ )
+ {
+ }
+
+ fn new<SystemImpl>(
+ _system: &'world impl System<'world, SystemImpl>,
+ world_data: &'world WorldData,
+ ) -> Self
+ {
+ let sole = world_data
+ .sole_storage
+ .get::<SoleT>()
+ .expect("Sole was not found in world")
+ .write_nonblock()
+ .unwrap_or_else(|_| {
+ panic!(
+ "Failed to aquire read-write lock to single component {}",
+ type_name::<SoleT>()
+ )
+ });
+
+ Self { sole, _ph: PhantomData }
+ }
+
+ fn is_compatible<Other: SystemParam<'world>>() -> bool
+ {
+ let other_comparable = Other::get_comparable();
+
+ let Some(comparable) = other_comparable.downcast_ref::<Comparable>() else {
+ // The other system param is not Single
+ return true;
+ };
+
+ TypeId::of::<SoleT>() != comparable.sole_type_id
+ }
+
+ fn get_comparable() -> Box<dyn Any>
+ {
+ Box::new(Comparable { sole_type_id: TypeId::of::<SoleT>() })
+ }
+}
+
+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,
+}