diff options
author | HampusM <hampus@hampusmat.com> | 2024-06-16 13:17:57 +0200 |
---|---|---|
committer | HampusM <hampus@hampusmat.com> | 2024-06-16 13:17:57 +0200 |
commit | d50a2f6e63c25adf3b64652310c423717bd3966f (patch) | |
tree | 3edf4ee3d1eec93a52a8de4fdc5a7be5c487c711 | |
parent | 69d90ece7f54996f0f51fc120a38d37717c5248e (diff) |
refactor(ecs): add component ID struct
-rw-r--r-- | ecs/src/component.rs | 37 | ||||
-rw-r--r-- | ecs/src/component/local.rs | 10 | ||||
-rw-r--r-- | ecs/src/component/storage.rs | 62 | ||||
-rw-r--r-- | ecs/src/lib.rs | 4 | ||||
-rw-r--r-- | ecs/src/query.rs | 25 | ||||
-rw-r--r-- | ecs/src/system/stateful.rs | 8 |
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)) ); } |