diff options
Diffstat (limited to 'engine-ecs/src/sole.rs')
| -rw-r--r-- | engine-ecs/src/sole.rs | 107 |
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, +} |
