summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--ecs/examples/with_single.rs59
-rw-r--r--ecs/src/component.rs1
-rw-r--r--ecs/src/component/single.rs98
-rw-r--r--ecs/src/lib.rs49
-rw-r--r--ecs/src/sole.rs134
5 files changed, 154 insertions, 187 deletions
diff --git a/ecs/examples/with_single.rs b/ecs/examples/with_single.rs
deleted file mode 100644
index d222f76..0000000
--- a/ecs/examples/with_single.rs
+++ /dev/null
@@ -1,59 +0,0 @@
-use ecs::component::single::Single;
-use ecs::event::Event;
-use ecs::{Component, Query, World};
-
-#[derive(Component)]
-struct Ammo
-{
- ammo_left: u32,
-}
-
-#[derive(Component, Default)]
-struct AmmoCounter
-{
- counter: u32,
-}
-
-fn count_ammo(query: Query<(Ammo,)>, mut ammo_counter: Single<AmmoCounter>)
-{
- for (ammo,) in &query {
- println!("Found {} ammo", ammo.ammo_left);
-
- ammo_counter.counter += ammo.ammo_left;
- }
-}
-
-fn print_total_ammo_count(ammo_counter: Single<AmmoCounter>)
-{
- println!("Total ammo count: {}", ammo_counter.counter);
-
- assert_eq!(ammo_counter.counter, 19);
-}
-
-#[derive(Debug)]
-struct EventA;
-
-impl Event for EventA {}
-
-#[derive(Debug)]
-struct EventB;
-
-impl Event for EventB {}
-
-fn main()
-{
- let mut world = World::new();
-
- world.register_system(EventA, count_ammo);
- world.register_system(EventB, print_total_ammo_count);
-
- world.create_entity((Ammo { ammo_left: 4 },));
- world.create_entity((Ammo { ammo_left: 7 },));
- world.create_entity((Ammo { ammo_left: 8 },));
-
- world.add_single_component(AmmoCounter::default()).unwrap();
-
- world.emit(EventA);
-
- world.emit(EventB);
-}
diff --git a/ecs/src/component.rs b/ecs/src/component.rs
index 0e5f020..7a61f39 100644
--- a/ecs/src/component.rs
+++ b/ecs/src/component.rs
@@ -8,7 +8,6 @@ use crate::system::{ComponentRefMut, Input as SystemInput};
use crate::type_name::TypeName;
pub mod local;
-pub mod single;
pub trait Component: SystemInput + Any + TypeName
{
diff --git a/ecs/src/component/single.rs b/ecs/src/component/single.rs
deleted file mode 100644
index a63dbe3..0000000
--- a/ecs/src/component/single.rs
+++ /dev/null
@@ -1,98 +0,0 @@
-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,
-}
diff --git a/ecs/src/lib.rs b/ecs/src/lib.rs
index c93781d..e568fb8 100644
--- a/ecs/src/lib.rs
+++ b/ecs/src/lib.rs
@@ -13,6 +13,7 @@ use crate::actions::Action;
use crate::component::{Component, Sequence as ComponentSequence};
use crate::event::{Event, Id as EventId, Ids, Sequence as EventSequence};
use crate::lock::Lock;
+use crate::sole::Sole;
use crate::system::{System, TypeErased as TypeErasedSystem};
use crate::type_name::TypeName;
@@ -21,6 +22,7 @@ pub mod component;
pub mod event;
pub mod lock;
pub mod query;
+pub mod sole;
pub mod system;
pub mod tuple;
pub mod type_name;
@@ -89,18 +91,15 @@ impl World
});
}
- /// Adds a single component. This component will be globally shared.
+ /// Adds a globally shared singleton value.
///
/// # Errors
- /// Returns `Err` if this component has already been added as a single component.
- pub fn add_single_component<SingleComponent>(
- &mut self,
- single_component: SingleComponent,
- ) -> Result<(), SingleComponentAlreadyExistsError>
+ /// Returns `Err` if this [`Sole`] has already been added.
+ pub fn add_sole<SoleT>(&mut self, sole: SoleT) -> Result<(), SoleAlreadyExistsError>
where
- SingleComponent: Component,
+ SoleT: Sole,
{
- self.data.single_component_storage.insert(single_component)
+ self.data.sole_storage.insert(sole)
}
pub fn register_system<'this, EventT, SystemImpl>(
@@ -227,7 +226,7 @@ pub struct WorldData
{
events: HashMap<EventId, Vec<usize>>,
component_storage: Arc<Lock<ComponentStorage>>,
- single_component_storage: SingleComponentStorage,
+ sole_storage: SoleStorage,
action_queue: Arc<Lock<ActionQueue>>,
}
@@ -348,39 +347,31 @@ impl Drop for ComponentStorage
}
#[derive(Debug, thiserror::Error)]
-#[error("Single component {0} already exists")]
-pub struct SingleComponentAlreadyExistsError(pub &'static str);
+#[error("Sole {0} already exists")]
+pub struct SoleAlreadyExistsError(pub &'static str);
#[derive(Debug, Default)]
-struct SingleComponentStorage
+struct SoleStorage
{
- storage: HashMap<TypeId, Lock<Box<dyn Component>>>,
+ storage: HashMap<TypeId, Lock<Box<dyn Sole>>>,
}
-impl SingleComponentStorage
+impl SoleStorage
{
- fn get<SingleComponent: Component>(&self) -> Option<&Lock<Box<dyn Component>>>
+ fn get<SoleT: Sole>(&self) -> Option<&Lock<Box<dyn Sole>>>
{
- self.storage.get(&TypeId::of::<SingleComponent>())
+ self.storage.get(&TypeId::of::<SoleT>())
}
- fn insert<SingleComponent: Component>(
- &mut self,
- single_component: SingleComponent,
- ) -> Result<(), SingleComponentAlreadyExistsError>
+ fn insert<SoleT: Sole>(&mut self, sole: SoleT) -> Result<(), SoleAlreadyExistsError>
{
- let single_component_type_id = TypeId::of::<SingleComponent>();
+ let sole_type_id = TypeId::of::<SoleT>();
- if self.storage.contains_key(&single_component_type_id) {
- return Err(SingleComponentAlreadyExistsError(type_name::<
- SingleComponent,
- >()));
+ if self.storage.contains_key(&sole_type_id) {
+ return Err(SoleAlreadyExistsError(type_name::<SoleT>()));
}
- self.storage.insert(
- single_component_type_id,
- Lock::new(Box::new(single_component)),
- );
+ self.storage.insert(sole_type_id, Lock::new(Box::new(sole)));
Ok(())
}
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,
+}