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 /ecs/src | |
| parent | 69d90ece7f54996f0f51fc120a38d37717c5248e (diff) | |
refactor(ecs): add component ID struct
Diffstat (limited to 'ecs/src')
| -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))                          );                  }  | 
