summaryrefslogtreecommitdiff
path: root/engine-ecs/src/sole.rs
diff options
context:
space:
mode:
Diffstat (limited to 'engine-ecs/src/sole.rs')
-rw-r--r--engine-ecs/src/sole.rs107
1 files changed, 107 insertions, 0 deletions
diff --git a/engine-ecs/src/sole.rs b/engine-ecs/src/sole.rs
new file mode 100644
index 0000000..1e287d3
--- /dev/null
+++ b/engine-ecs/src/sole.rs
@@ -0,0 +1,107 @@
+use std::any::{type_name, Any};
+use std::fmt::Debug;
+
+use crate::component::{
+ HandleMut as ComponentHandleMut,
+ IntoParts as IntoComponentParts,
+};
+use crate::system::{Metadata as SystemMetadata, Param as SystemParam};
+use crate::uid::Uid;
+use crate::World;
+
+/// A component which has a single instance in the [`World`].
+pub trait Sole: Any + IntoComponentParts
+{
+ fn id() -> Uid
+ where
+ Self: Sized;
+
+ fn type_reflection() -> Option<&'static crate::reflection::Type>
+ where
+ Self: Sized;
+
+ /// Returns the name of this component.
+ fn name(&self) -> &'static str;
+}
+
+impl dyn Sole
+{
+ pub fn downcast_mut<Real: 'static>(&mut self) -> Option<&mut Real>
+ {
+ (self as &mut dyn Any).downcast_mut()
+ }
+
+ pub fn downcast_ref<Real: 'static>(&self) -> Option<&Real>
+ {
+ (self as &dyn Any).downcast_ref()
+ }
+
+ pub fn is<Other: 'static>(&self) -> bool
+ {
+ (self as &dyn Any).is::<Other>()
+ }
+}
+
+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 singleton component.
+#[derive(Debug)]
+pub struct Single<'world, SoleT: Sole>
+{
+ sole: Option<ComponentHandleMut<'world, SoleT>>,
+}
+
+impl<'world, SoleT> Single<'world, SoleT>
+where
+ SoleT: Sole,
+{
+ /// Returns a reference to `SoleT` if it exists. If not, returns `Err`.
+ pub fn get(&self) -> Result<&SoleT, DoesNotExistError>
+ {
+ self.sole
+ .as_deref()
+ .ok_or_else(|| DoesNotExistError { name: type_name::<SoleT>() })
+ }
+
+ /// Returns a mutable reference to `SoleT` if it exists. If not, returns `Err`.
+ pub fn get_mut(&mut self) -> Result<&mut SoleT, DoesNotExistError>
+ {
+ self.sole
+ .as_deref_mut()
+ .ok_or_else(|| DoesNotExistError { name: type_name::<SoleT>() })
+ }
+
+ pub(crate) fn new(world: &'world World) -> Self
+ {
+ let sole = world
+ .get_entity(SoleT::id())
+ .and_then(|ent| ent.get_with_id_mut::<SoleT>(SoleT::id()));
+
+ Self { sole }
+ }
+}
+
+impl<'world, SoleT> SystemParam<'world> for Single<'world, SoleT>
+where
+ SoleT: Sole,
+{
+ type Input = ();
+
+ fn new(world: &'world World, _system_metadata: &SystemMetadata) -> Self
+ {
+ Self::new(world)
+ }
+}
+
+#[derive(Debug, thiserror::Error)]
+#[error("Sole {name} does not exist")]
+pub struct DoesNotExistError
+{
+ pub name: &'static str,
+}