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(&mut self) -> Option<&mut Real> { (self as &mut dyn Any).downcast_mut() } pub fn downcast_ref(&self) -> Option<&Real> { (self as &dyn Any).downcast_ref() } pub fn is(&self) -> bool { (self as &dyn Any).is::() } } 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>, } 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::() }) } /// 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::() }) } pub(crate) fn new(world: &'world World) -> Self { let sole = world .get_entity(SoleT::id()) .and_then(|ent| ent.get_with_id_mut::(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, }