summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorHampusM <hampus@hampusmat.com>2024-06-16 13:17:57 +0200
committerHampusM <hampus@hampusmat.com>2024-06-16 13:17:57 +0200
commitd50a2f6e63c25adf3b64652310c423717bd3966f (patch)
tree3edf4ee3d1eec93a52a8de4fdc5a7be5c487c711
parent69d90ece7f54996f0f51fc120a38d37717c5248e (diff)
refactor(ecs): add component ID struct
-rw-r--r--ecs/src/component.rs37
-rw-r--r--ecs/src/component/local.rs10
-rw-r--r--ecs/src/component/storage.rs62
-rw-r--r--ecs/src/lib.rs4
-rw-r--r--ecs/src/query.rs25
-rw-r--r--ecs/src/system/stateful.rs8
6 files changed, 84 insertions, 62 deletions
diff --git a/ecs/src/component.rs b/ecs/src/component.rs
index 5c0b9ce..512c60d 100644
--- a/ecs/src/component.rs
+++ b/ecs/src/component.rs
@@ -15,7 +15,7 @@ pub(crate) mod storage;
pub trait Component: SystemInput + Any + TypeName
{
/// The component type in question. Will usually be `Self`
- type Component
+ type Component: Component
where
Self: Sized;
@@ -23,6 +23,9 @@ pub trait Component: SystemInput + Any + TypeName
where
Self: Sized;
+ /// Returns the ID of this component's type.
+ fn id(&self) -> Id;
+
#[doc(hidden)]
fn as_any_mut(&mut self) -> &mut dyn Any;
@@ -76,6 +79,11 @@ where
type Component = ComponentT;
type RefMut<'component> = Option<ComponentRefMut<'component, ComponentT>>;
+ fn id(&self) -> Id
+ {
+ Id::of::<Self>()
+ }
+
fn as_any_mut(&mut self) -> &mut dyn Any
{
self
@@ -104,6 +112,23 @@ where
impl<ComponentT> SystemInput for Option<ComponentT> where ComponentT: Component {}
+/// The ID of a [`Component`] type.
+#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
+pub struct Id
+{
+ inner: TypeId,
+}
+
+impl Id
+{
+ pub fn of<ComponentT>() -> Self
+ where
+ ComponentT: Component,
+ {
+ Self { inner: TypeId::of::<ComponentT>() }
+ }
+}
+
/// A sequence of components.
pub trait Sequence
{
@@ -113,7 +138,7 @@ pub trait Sequence
fn into_vec(self) -> Vec<Box<dyn Component>>;
- fn type_ids() -> Vec<(TypeId, IsOptional)>;
+ fn ids() -> Vec<(Id, IsOptional)>;
fn from_components<'component>(
components: impl Iterator<Item = &'component EntityComponent>,
@@ -145,7 +170,7 @@ impl From<bool> for IsOptional
/// Will return `true` if the component is a [`Option`].
pub fn is_optional<ComponentT: Component>() -> bool
{
- if TypeId::of::<ComponentT>() == TypeId::of::<Option<ComponentT::Component>>() {
+ if Id::of::<ComponentT>() == Id::of::<Option<ComponentT::Component>>() {
return true;
}
@@ -174,11 +199,11 @@ macro_rules! inner {
Vec::from_iter([#(Box::new(self.I) as Box<dyn Component>,)*])
}
- fn type_ids() -> Vec<(TypeId, IsOptional)>
+ fn ids() -> Vec<(Id, IsOptional)>
{
vec![
#(
- (TypeId::of::<Comp~I>(), is_optional::<Comp~I>().into()),
+ (Id::of::<Comp~I>(), is_optional::<Comp~I>().into()),
)*
]
}
@@ -193,7 +218,7 @@ macro_rules! inner {
for comp in components {
#(
- if comp.id == TypeId::of::<Comp~I::Component>() {
+ if comp.id == Id::of::<Comp~I::Component>() {
comp_~I = Some(lock_component(comp));
continue;
}
diff --git a/ecs/src/component/local.rs b/ecs/src/component/local.rs
index e1a0c1f..89c3139 100644
--- a/ecs/src/component/local.rs
+++ b/ecs/src/component/local.rs
@@ -1,7 +1,7 @@
-use std::any::{Any, TypeId};
+use std::any::Any;
use std::ops::{Deref, DerefMut};
-use crate::component::Component;
+use crate::component::{Component, Id};
use crate::system::{ComponentRefMut, Param as SystemParam, System};
use crate::WorldData;
@@ -43,16 +43,16 @@ where
{
let other_comparable = Other::get_comparable();
- let Some(other_type_id) = other_comparable.downcast_ref::<TypeId>() else {
+ let Some(other_id) = other_comparable.downcast_ref::<Id>() else {
return true;
};
- TypeId::of::<LocalComponent>() != *other_type_id
+ Id::of::<LocalComponent>() != *other_id
}
fn get_comparable() -> Box<dyn Any>
{
- Box::new(TypeId::of::<LocalComponent>())
+ Box::new(Id::of::<LocalComponent>())
}
}
diff --git a/ecs/src/component/storage.rs b/ecs/src/component/storage.rs
index cc9e911..bd53da0 100644
--- a/ecs/src/component/storage.rs
+++ b/ecs/src/component/storage.rs
@@ -1,9 +1,9 @@
-use std::any::{type_name, TypeId};
+use std::any::type_name;
use std::collections::{HashMap, HashSet};
use std::hash::{DefaultHasher, Hash, Hasher};
use std::ptr::NonNull;
-use crate::component::{Component, IsOptional as ComponentIsOptional};
+use crate::component::{Component, Id as ComponentId, IsOptional as ComponentIsOptional};
use crate::lock::Lock;
use crate::type_name::TypeName;
use crate::EntityComponent;
@@ -13,14 +13,14 @@ pub struct ComponentStorage
{
archetypes: Vec<Archetype>,
archetype_lookup: HashMap<ArchetypeComponentsHash, Vec<NonNull<Archetype>>>,
- pending_archetype_lookup_entries: Vec<Vec<TypeId>>,
+ pending_archetype_lookup_entries: Vec<Vec<ComponentId>>,
}
impl ComponentStorage
{
pub fn find_entities(
&self,
- component_ids: &[(TypeId, ComponentIsOptional)],
+ component_ids: &[(ComponentId, ComponentIsOptional)],
) -> Option<&[&Archetype]>
{
let ids = component_ids
@@ -63,7 +63,7 @@ impl ComponentStorage
components
.iter()
.filter(|component| !component.is_optional())
- .map(|component| (*component).type_id()),
+ .map(|component| component.id()),
))
.or_insert_with(|| {
self.archetypes.push(Archetype::default());
@@ -83,13 +83,13 @@ impl ComponentStorage
archetype
.component_ids
- .extend(components.iter().map(|component| (*component).type_id()));
+ .extend(components.iter().map(|component| component.id()));
archetype.components.push(
components
.into_iter()
.map(|component| EntityComponent {
- id: (*component).type_id(),
+ id: component.id(),
name: component.type_name(),
component: Lock::new(component),
})
@@ -97,7 +97,7 @@ impl ComponentStorage
);
}
- pub fn add_archetype_lookup_entry(&mut self, component_ids: &[TypeId])
+ pub fn add_archetype_lookup_entry(&mut self, component_ids: &[ComponentId])
{
self.pending_archetype_lookup_entries
.push(component_ids.to_vec());
@@ -142,7 +142,7 @@ impl TypeName for ComponentStorage
#[derive(Debug, Default)]
pub struct Archetype
{
- component_ids: HashSet<TypeId>,
+ component_ids: HashSet<ComponentId>,
pub components: Vec<Vec<EntityComponent>>,
}
@@ -154,7 +154,7 @@ struct ArchetypeComponentsHash
impl ArchetypeComponentsHash
{
- fn new(component_ids: impl IntoIterator<Item = TypeId>) -> Self
+ fn new(component_ids: impl IntoIterator<Item = ComponentId>) -> Self
{
let mut hasher = DefaultHasher::new();
@@ -181,13 +181,13 @@ const unsafe fn nonnull_slice_to_ref_slice<Item>(slice: &[NonNull<Item>]) -> &[&
#[cfg(test)]
mod tests
{
- use std::any::TypeId;
use std::collections::HashSet;
use std::ptr::addr_of;
use ecs_macros::Component;
use super::{Archetype, ArchetypeComponentsHash, ComponentStorage};
+ use crate::component::Id as ComponentId;
use crate::lock::Lock;
use crate::{self as ecs, EntityComponent};
@@ -252,8 +252,8 @@ mod tests
let lookup = component_storage
.archetype_lookup
.get(&ArchetypeComponentsHash::new([
- TypeId::of::<HealthPotion>(),
- TypeId::of::<Hookshot>(),
+ ComponentId::of::<HealthPotion>(),
+ ComponentId::of::<Hookshot>(),
]))
.expect("Expected entry in archetype lookup map");
@@ -274,23 +274,23 @@ mod tests
component_storage.archetypes.push(Archetype {
component_ids: HashSet::from([
- TypeId::of::<IronBoots>(),
- TypeId::of::<HealthPotion>(),
- TypeId::of::<Hookshot>(),
+ ComponentId::of::<IronBoots>(),
+ ComponentId::of::<HealthPotion>(),
+ ComponentId::of::<Hookshot>(),
]),
components: vec![
vec![EntityComponent {
- id: TypeId::of::<IronBoots>(),
+ id: ComponentId::of::<IronBoots>(),
name: "Iron boots",
component: Lock::new(Box::new(IronBoots)),
}],
vec![EntityComponent {
- id: TypeId::of::<HealthPotion>(),
+ id: ComponentId::of::<HealthPotion>(),
name: "Health potion",
component: Lock::new(Box::new(HealthPotion { _hp_restoration: 20 })),
}],
vec![EntityComponent {
- id: TypeId::of::<Hookshot>(),
+ id: ComponentId::of::<Hookshot>(),
name: "Hookshot",
component: Lock::new(Box::new(Hookshot { _range: 67 })),
}],
@@ -299,29 +299,29 @@ mod tests
component_storage.archetypes.push(Archetype {
component_ids: HashSet::from([
- TypeId::of::<DekuNut>(),
- TypeId::of::<IronBoots>(),
- TypeId::of::<Bow>(),
- TypeId::of::<Hookshot>(),
+ ComponentId::of::<DekuNut>(),
+ ComponentId::of::<IronBoots>(),
+ ComponentId::of::<Bow>(),
+ ComponentId::of::<Hookshot>(),
]),
components: vec![
vec![EntityComponent {
- id: TypeId::of::<DekuNut>(),
+ id: ComponentId::of::<DekuNut>(),
name: "Deku nut",
component: Lock::new(Box::new(DekuNut { _throwing_damage: 5 })),
}],
vec![EntityComponent {
- id: TypeId::of::<IronBoots>(),
+ id: ComponentId::of::<IronBoots>(),
name: "Iron boots",
component: Lock::new(Box::new(IronBoots)),
}],
vec![EntityComponent {
- id: TypeId::of::<Bow>(),
+ id: ComponentId::of::<Bow>(),
name: "Bow",
component: Lock::new(Box::new(Bow { _damage: 20 })),
}],
vec![EntityComponent {
- id: TypeId::of::<Hookshot>(),
+ id: ComponentId::of::<Hookshot>(),
name: "Hookshot",
component: Lock::new(Box::new(Hookshot { _range: 67 })),
}],
@@ -329,8 +329,8 @@ mod tests
});
component_storage.add_archetype_lookup_entry(&[
- TypeId::of::<IronBoots>(),
- TypeId::of::<Hookshot>(),
+ ComponentId::of::<IronBoots>(),
+ ComponentId::of::<Hookshot>(),
]);
assert_eq!(component_storage.pending_archetype_lookup_entries.len(), 1);
@@ -342,8 +342,8 @@ mod tests
let archetypes = component_storage
.archetype_lookup
.get(&ArchetypeComponentsHash::new([
- TypeId::of::<IronBoots>(),
- TypeId::of::<Hookshot>(),
+ ComponentId::of::<IronBoots>(),
+ ComponentId::of::<Hookshot>(),
]))
.expect(concat!(
"Expected a archetype for IronBoots & Hookshot to be found in the ",
diff --git a/ecs/src/lib.rs b/ecs/src/lib.rs
index 0dd1c02..e427150 100644
--- a/ecs/src/lib.rs
+++ b/ecs/src/lib.rs
@@ -11,7 +11,7 @@ use std::vec::Drain;
use crate::actions::Action;
use crate::component::storage::ComponentStorage;
-use crate::component::{Component, Sequence as ComponentSequence};
+use crate::component::{Component, Id as ComponentId, Sequence as ComponentSequence};
use crate::event::{Event, Id as EventId, Ids, Sequence as EventSequence};
use crate::extension::{Collector as ExtensionCollector, Extension};
use crate::lock::Lock;
@@ -212,7 +212,7 @@ pub struct WorldData
#[non_exhaustive]
pub struct EntityComponent
{
- pub id: TypeId,
+ pub id: ComponentId,
pub name: &'static str,
pub component: Lock<Box<dyn Component>>,
}
diff --git a/ecs/src/query.rs b/ecs/src/query.rs
index de6c832..a2edc4d 100644
--- a/ecs/src/query.rs
+++ b/ecs/src/query.rs
@@ -1,4 +1,4 @@
-use std::any::{type_name, Any, TypeId};
+use std::any::{type_name, Any};
use std::collections::HashSet;
use std::iter::{Flatten, Map};
use std::marker::PhantomData;
@@ -7,6 +7,7 @@ use std::sync::{Arc, Weak};
use crate::component::storage::Archetype;
use crate::component::{
+ Id as ComponentId,
IsOptional as ComponentIsOptional,
Sequence as ComponentSequence,
};
@@ -43,7 +44,7 @@ where
ComponentIter {
entities: self
.component_storage
- .find_entities(&Comps::type_ids())
+ .find_entities(&Comps::ids())
.unwrap_or_else(|| panic!("Could not find {:?}", type_name::<Comps>()))
.iter()
.map((|archetype| archetype.components.as_slice()) as ComponentIterMapFn)
@@ -124,9 +125,7 @@ where
fn get_comparable() -> Box<dyn Any>
{
- Box::new(QueryComponentIds {
- component_type_ids: Comps::type_ids(),
- })
+ Box::new(QueryComponentIds { component_ids: Comps::ids() })
}
fn handle_pre_run(world_data: &WorldData)
@@ -143,7 +142,7 @@ where
);
component_storage_lock.add_archetype_lookup_entry(
- &Comps::type_ids()
+ &Comps::ids()
.into_iter()
.filter_map(|(component_id, is_optional)| {
if is_optional == ComponentIsOptional::Yes {
@@ -242,7 +241,7 @@ where
#[derive(Debug)]
struct QueryComponentIds
{
- component_type_ids: Vec<(TypeId, ComponentIsOptional)>,
+ component_ids: Vec<(ComponentId, ComponentIsOptional)>,
}
impl QueryComponentIds
@@ -251,15 +250,13 @@ impl QueryComponentIds
where
OtherComps: ComponentSequence,
{
- let other_component_type_ids = OtherComps::type_ids()
+ let other_ids = OtherComps::ids()
.into_iter()
- .map(|(type_id, _)| type_id)
- .collect::<HashSet<TypeId>>();
+ .map(|(id, _)| id)
+ .collect::<HashSet<_>>();
- self.component_type_ids
+ self.component_ids
.iter()
- .all(|(component_type_id, _)| {
- other_component_type_ids.contains(component_type_id)
- })
+ .all(|(id, _)| other_ids.contains(id))
}
}
diff --git a/ecs/src/system/stateful.rs b/ecs/src/system/stateful.rs
index b765ff0..ae6a5b5 100644
--- a/ecs/src/system/stateful.rs
+++ b/ecs/src/system/stateful.rs
@@ -4,7 +4,7 @@ use std::panic::{RefUnwindSafe, UnwindSafe};
use seq_macro::seq;
-use crate::component::Component;
+use crate::component::{Component, Id as ComponentId};
use crate::lock::Lock;
use crate::system::util::check_params_are_compatible;
use crate::system::{
@@ -27,7 +27,7 @@ use crate::WorldData;
pub struct Stateful<Func>
{
func: Func,
- local_components: HashMap<TypeId, Lock<Box<dyn Component>>>,
+ local_components: HashMap<ComponentId, Lock<Box<dyn Component>>>,
}
macro_rules! impl_system {
@@ -134,7 +134,7 @@ macro_rules! impl_system {
) -> Option<ComponentRefMut<LocalComponent>>
{
let local_component = self.local_components
- .get(&TypeId::of::<LocalComponent>())?
+ .get(&ComponentId::of::<LocalComponent>())?
.write_nonblock()
.expect("Failed to aquire read-write local component lock");
@@ -148,7 +148,7 @@ macro_rules! impl_system {
{
self.local_components
.insert(
- TypeId::of::<LocalComponent>(),
+ ComponentId::of::<LocalComponent>(),
Lock::new(Box::new(local_component))
);
}