summaryrefslogtreecommitdiff
path: root/engine-ecs
diff options
context:
space:
mode:
authorHampusM <hampus@hampusmat.com>2026-06-20 16:01:00 +0200
committerHampusM <hampus@hampusmat.com>2026-06-23 00:25:26 +0200
commit7b3374ad9585f78c60e1b158126ab54384a83f32 (patch)
treeee14cd0bebd6554fab43685da89c459310f0e97d /engine-ecs
parentd6cf708a4fd1caf0f2e193ceb7c23fa8e77cc1db (diff)
refactor(engine-ecs): store soles as components
Diffstat (limited to 'engine-ecs')
-rw-r--r--engine-ecs/src/component.rs17
-rw-r--r--engine-ecs/src/lib.rs87
-rw-r--r--engine-ecs/src/sole.rs57
3 files changed, 41 insertions, 120 deletions
diff --git a/engine-ecs/src/component.rs b/engine-ecs/src/component.rs
index 157d79c..25ec101 100644
--- a/engine-ecs/src/component.rs
+++ b/engine-ecs/src/component.rs
@@ -1,4 +1,4 @@
-use std::any::{type_name, Any};
+use std::any::Any;
use std::fmt::Debug;
use std::ops::{Deref, DerefMut};
@@ -24,7 +24,7 @@ pub mod local;
pub(crate) mod storage;
-pub trait Component: SystemInput + Any
+pub trait Component: SystemInput + Any + IntoParts
{
/// Returns the ID of this component.
fn id() -> Uid
@@ -286,19 +286,6 @@ pub trait IntoParts
fn into_parts(self) -> Parts;
}
-impl<ComponentT> IntoParts for ComponentT
-where
- ComponentT: Component,
-{
- fn into_parts(self) -> Parts
- {
- Parts::builder()
- .name(type_name::<Self>())
- .type_reflection(Self::type_reflection())
- .build(Self::id(), self)
- }
-}
-
/// The parts of a component.
#[derive(Debug)]
#[non_exhaustive]
diff --git a/engine-ecs/src/lib.rs b/engine-ecs/src/lib.rs
index 1c157e3..25866ca 100644
--- a/engine-ecs/src/lib.rs
+++ b/engine-ecs/src/lib.rs
@@ -1,14 +1,10 @@
#![deny(clippy::all, clippy::pedantic)]
-use std::any::{type_name, Any, TypeId};
+use std::any::Any;
use std::fmt::Debug;
use std::hint::cold_path;
-use std::mem::ManuallyDrop;
use std::rc::Rc;
use std::sync::atomic::{AtomicBool, Ordering};
-use std::sync::Arc;
-
-use hashbrown::HashMap;
use crate::actions::Action;
use crate::component::storage::archetype::EntityComponent as ArchetypeEntityComponent;
@@ -156,7 +152,7 @@ impl World
entity_decl.create(self);
}
- /// Adds a globally shared singleton value.
+ /// Adds a singleton.
///
/// # Errors
/// Returns `Err` if this [`Sole`] has already been added.
@@ -164,7 +160,9 @@ impl World
where
SoleT: Sole,
{
- self.data.sole_storage.insert(sole)
+ self.create_ent(SoleT::id(), [sole.into_parts()]);
+
+ Ok(())
}
pub fn register_observer<'this, SystemImpl, ObserverT>(
@@ -253,7 +251,9 @@ impl World
pub fn get_sole<SoleT: Sole>(&self) -> Option<Single<'_, SoleT>>
{
- Some(Single::new(self.data.sole_storage.get::<SoleT>()?))
+ let ent = self.get_entity(SoleT::id())?;
+
+ Some(Single::new(ent.get_with_id_mut(SoleT::id())?))
}
pub fn event_submitter(&self) -> EventSubmitter<'_>
@@ -701,7 +701,6 @@ pub enum StepResult
struct WorldData
{
component_storage: ComponentStorage,
- sole_storage: SoleStorage,
action_queue: Rc<ActionQueue>,
new_events: Lock<NewEvents>,
}
@@ -765,73 +764,3 @@ impl ActionQueue
#[error("Sole {0} already exists")]
pub struct SoleAlreadyExistsError(pub &'static str);
-#[derive(Debug)]
-struct StoredSole
-{
- sole: Arc<Lock<Box<dyn Sole>>>,
- drop_last: bool,
-}
-
-#[derive(Debug, Default)]
-struct SoleStorage
-{
- storage: HashMap<TypeId, ManuallyDrop<StoredSole>>,
-}
-
-impl SoleStorage
-{
- fn get<SoleT: Sole>(&self) -> Option<&Arc<Lock<Box<dyn Sole>>>>
- {
- self.storage
- .get(&TypeId::of::<SoleT>())
- .map(|sole| &sole.sole)
- }
-
- fn insert<SoleT: Sole>(&mut self, sole: SoleT) -> Result<(), SoleAlreadyExistsError>
- {
- let sole_type_id = TypeId::of::<SoleT>();
-
- if self.storage.contains_key(&sole_type_id) {
- return Err(SoleAlreadyExistsError(type_name::<SoleT>()));
- }
-
- let drop_last = sole.drop_last();
-
- // TODO: Reconsider this maybe?
- #[allow(clippy::arc_with_non_send_sync)]
- self.storage.insert(
- sole_type_id,
- ManuallyDrop::new(StoredSole {
- sole: Arc::new(Lock::new(Box::new(sole), type_name::<SoleT>())),
- drop_last,
- }),
- );
-
- Ok(())
- }
-}
-
-impl Drop for SoleStorage
-{
- fn drop(&mut self)
- {
- let mut soles_to_drop_last = Vec::new();
-
- for sole in self.storage.values_mut() {
- if sole.drop_last {
- soles_to_drop_last.push(sole);
- continue;
- }
-
- unsafe {
- ManuallyDrop::drop(sole);
- }
- }
-
- for sole in &mut soles_to_drop_last {
- unsafe {
- ManuallyDrop::drop(sole);
- }
- }
- }
-}
diff --git a/engine-ecs/src/sole.rs b/engine-ecs/src/sole.rs
index 9e27fee..9409bcb 100644
--- a/engine-ecs/src/sole.rs
+++ b/engine-ecs/src/sole.rs
@@ -1,33 +1,43 @@
use std::any::{type_name, Any};
use std::fmt::Debug;
-use std::marker::PhantomData;
use std::ops::{Deref, DerefMut};
-use std::sync::Arc;
-use crate::lock::{Lock, WriteGuard};
+use crate::uid::Uid;
+use crate::component::HandleMut as ComponentHandleMut;
+use crate::component::IntoParts as IntoComponentParts;
use crate::system::{Metadata as SystemMetadata, Param as SystemParam};
use crate::World;
/// A type which has a single instance and is shared globally.
-pub trait Sole: Any
+pub trait Sole: Any + IntoComponentParts
{
- fn drop_last(&self) -> bool;
+ fn id() -> Uid
+ where
+ Self: Sized;
- fn as_any_mut(&mut self) -> &mut dyn Any;
+ fn type_reflection() -> Option<&'static crate::reflection::Type>
+ where
+ Self: Sized;
- fn as_any(&self) -> &dyn Any;
+ /// 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_any_mut().downcast_mut()
+ (self as &mut dyn Any).downcast_mut()
}
pub fn downcast_ref<Real: 'static>(&self) -> Option<&Real>
{
- self.as_any().downcast_ref()
+ (self as &dyn Any).downcast_ref()
+ }
+
+ pub fn is<Other: 'static>(&self) -> bool
+ {
+ (self as &dyn Any).is::<Other>()
}
}
@@ -43,25 +53,17 @@ impl Debug for dyn Sole
#[derive(Debug)]
pub struct Single<'world, SoleT: Sole>
{
- sole: WriteGuard<'world, Box<dyn Sole>>,
- _ph: PhantomData<SoleT>,
+ sole: ComponentHandleMut<'world, SoleT>,
}
+
impl<'world, SoleT> Single<'world, SoleT>
where
SoleT: Sole,
{
- pub(crate) fn new(sole: &'world Arc<Lock<Box<dyn Sole>>>) -> Self
+ pub(crate) fn new(sole: ComponentHandleMut<'world, SoleT>) -> Self
{
- Self {
- sole: sole.write_nonblock().unwrap_or_else(|_| {
- panic!(
- "Failed to aquire read-write lock to single component {}",
- type_name::<SoleT>()
- )
- }),
- _ph: PhantomData,
- }
+ Self { sole }
}
}
@@ -73,9 +75,12 @@ where
fn new(world: &'world World, _system_metadata: &SystemMetadata) -> Self
{
- let sole = world.data.sole_storage.get::<SoleT>().unwrap_or_else(|| {
- panic!("Sole {} was not found in world", type_name::<SoleT>())
- });
+ let sole = world
+ .get_entity(SoleT::id())
+ .and_then(|ent| ent.get_with_id_mut::<SoleT>(SoleT::id()))
+ .unwrap_or_else(|| {
+ panic!("Sole component {} was not found in world", type_name::<SoleT>())
+ });
Self::new(sole)
}
@@ -89,7 +94,7 @@ where
fn deref(&self) -> &Self::Target
{
- self.sole.downcast_ref().unwrap()
+ &*self.sole
}
}
@@ -99,6 +104,6 @@ where
{
fn deref_mut(&mut self) -> &mut Self::Target
{
- self.sole.downcast_mut().unwrap()
+ &mut *self.sole
}
}