diff options
author | HampusM <hampus@hampusmat.com> | 2024-04-09 22:25:03 +0200 |
---|---|---|
committer | HampusM <hampus@hampusmat.com> | 2024-04-09 22:25:03 +0200 |
commit | 9d8c73dd2671131929967214433dae5479e95b5b (patch) | |
tree | d522d975e14e6db7544474b641d824edd8edbae5 /ecs/src/component | |
parent | 50234ddc9ee7acd6d2b8d0a5626caf9e9293c0da (diff) |
feat(ecs): add support for singleton components
Diffstat (limited to 'ecs/src/component')
-rw-r--r-- | ecs/src/component/single.rs | 98 |
1 files changed, 98 insertions, 0 deletions
diff --git a/ecs/src/component/single.rs b/ecs/src/component/single.rs new file mode 100644 index 0000000..a63dbe3 --- /dev/null +++ b/ecs/src/component/single.rs @@ -0,0 +1,98 @@ +use std::any::{type_name, Any, TypeId}; +use std::ops::{Deref, DerefMut}; + +use crate::component::Component; +use crate::system::{ComponentRefMut, NoInitParamFlag, Param as SystemParam, System}; +use crate::tuple::FilterExclude as TupleFilterExclude; +use crate::WorldData; + +/// Holds a component which has a single instance and is shared globally. +#[derive(Debug)] +pub struct Single<'world, SingleComponent: Component> +{ + single_component: ComponentRefMut<'world, SingleComponent>, +} + +unsafe impl<'world, SingleComponent> SystemParam<'world> + for Single<'world, SingleComponent> +where + SingleComponent: Component, +{ + 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 single_component = world_data + .single_component_storage + .get::<SingleComponent>() + .expect("Single component was not found in world") + .write_nonblock() + .unwrap_or_else(|_| { + panic!( + "Failed to aquire read-write lock to single component {}", + type_name::<SingleComponent>() + ) + }); + + Self { + single_component: ComponentRefMut::new(single_component), + } + } + + 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::<SingleComponent>() != comparable.single_component_type_id + } + + fn get_comparable() -> Box<dyn Any> + { + Box::new(Comparable { + single_component_type_id: TypeId::of::<SingleComponent>(), + }) + } +} + +impl<'world, SingleComponent> Deref for Single<'world, SingleComponent> +where + SingleComponent: Component, +{ + type Target = SingleComponent; + + fn deref(&self) -> &Self::Target + { + &self.single_component + } +} + +impl<'world, SingleComponent> DerefMut for Single<'world, SingleComponent> +where + SingleComponent: Component, +{ + fn deref_mut(&mut self) -> &mut Self::Target + { + &mut self.single_component + } +} + +struct Comparable +{ + single_component_type_id: TypeId, +} |