From caef866b4e3f87fd6ae2dd5b979a1fe1a1f3e5f2 Mon Sep 17 00:00:00 2001 From: HampusM Date: Sun, 3 Nov 2024 21:12:57 +0100 Subject: feat(ecs): add read-only query iterating --- ecs/src/relationship.rs | 185 +++++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 169 insertions(+), 16 deletions(-) (limited to 'ecs/src/relationship.rs') diff --git a/ecs/src/relationship.rs b/ecs/src/relationship.rs index 0fe776e..4db29da 100644 --- a/ecs/src/relationship.rs +++ b/ecs/src/relationship.rs @@ -4,12 +4,13 @@ use std::marker::PhantomData; use crate::component::storage::Storage as ComponentStorage; use crate::component::{ Component, - FromOptional as ComponentFromOptional, + FromOptional as FromOptionalComponent, + FromOptionalMut as FromOptionalMutComponent, Id as ComponentId, }; use crate::entity::Uid as EntityUid; use crate::lock::ReadGuard; -use crate::system::{ComponentRefMut, Input as SystemInput}; +use crate::system::{ComponentRef, ComponentRefMut, Input as SystemInput}; use crate::type_name::TypeName; use crate::World; @@ -52,7 +53,8 @@ where ComponentT: Component, { type Component = Self; - type RefMut<'component> = Relation<'component, Kind, ComponentT>; + type Ref<'component> = Relation<'component, Kind, ComponentT>; + type RefMut<'component> = RelationMut<'component, Kind, ComponentT>; fn id(&self) -> ComponentId { @@ -87,7 +89,7 @@ where } } -pub struct Relation<'rel_comp, Kind, ComponentT> +pub struct RelationMut<'rel_comp, Kind, ComponentT> where Kind: 'static, ComponentT: Component, @@ -96,12 +98,12 @@ where relationship_comp: ComponentRefMut<'rel_comp, Relationship>, } -impl<'rel_comp, Kind, ComponentT> ComponentFromOptional<'rel_comp> - for Relation<'rel_comp, Kind, ComponentT> +impl<'rel_comp, Kind, ComponentT> FromOptionalMutComponent<'rel_comp> + for RelationMut<'rel_comp, Kind, ComponentT> where ComponentT: Component, { - fn from_optional_component( + fn from_optional_mut_component( optional_component: Option< crate::lock::WriteGuard<'rel_comp, Box>, >, @@ -109,7 +111,7 @@ where ) -> Self { let relationship_comp = - ComponentRefMut::>::from_optional_component( + ComponentRefMut::>::from_optional_mut_component( optional_component, world, ); @@ -129,7 +131,7 @@ where } } -impl<'rel_comp, Kind, ComponentT> Relation<'rel_comp, Kind, ComponentT> +impl<'rel_comp, Kind, ComponentT> RelationMut<'rel_comp, Kind, ComponentT> where ComponentT: Component, { @@ -235,19 +237,19 @@ where /// Returns a iterator of the components of the targets of this relationship. #[must_use] - pub fn iter(&self) -> TargetComponentIter<'_, 'rel_comp, Kind, ComponentT> + pub fn iter(&self) -> TargetComponentIterMut<'_, 'rel_comp, Kind, ComponentT> { - TargetComponentIter { relation: self, index: 0 } + TargetComponentIterMut { relation: self, index: 0 } } } impl<'relationship, 'rel_comp, Kind, ComponentT> IntoIterator - for &'relationship Relation<'rel_comp, Kind, ComponentT> + for &'relationship RelationMut<'rel_comp, Kind, ComponentT> where 'relationship: 'rel_comp, ComponentT: Component, { - type IntoIter = TargetComponentIter<'relationship, 'rel_comp, Kind, ComponentT>; + type IntoIter = TargetComponentIterMut<'relationship, 'rel_comp, Kind, ComponentT>; type Item = ComponentRefMut<'rel_comp, ComponentT>; fn into_iter(self) -> Self::IntoIter @@ -257,17 +259,17 @@ where } /// Iterator of the components of the targets of a relationship. -pub struct TargetComponentIter<'relationship, 'rel_comp, Kind, ComponentT> +pub struct TargetComponentIterMut<'relationship, 'rel_comp, Kind, ComponentT> where Kind: 'static, ComponentT: Component, { - relation: &'relationship Relation<'rel_comp, Kind, ComponentT>, + relation: &'relationship RelationMut<'rel_comp, Kind, ComponentT>, index: usize, } impl<'relationship, 'rel_comp, Kind, ComponentT> Iterator - for TargetComponentIter<'relationship, 'rel_comp, Kind, ComponentT> + for TargetComponentIterMut<'relationship, 'rel_comp, Kind, ComponentT> where 'relationship: 'rel_comp, Kind: 'static, @@ -291,3 +293,154 @@ enum SingleOrMultiple Single(Value), Multiple(Vec), } + +pub struct Relation<'rel_comp, Kind, ComponentT> +where + Kind: 'static, + ComponentT: Component, +{ + component_storage_lock: ReadGuard<'static, ComponentStorage>, + relationship_comp: ComponentRef<'rel_comp, Relationship>, +} + +impl<'rel_comp, Kind, ComponentT> FromOptionalComponent<'rel_comp> + for Relation<'rel_comp, Kind, ComponentT> +where + ComponentT: Component, +{ + fn from_optional_component( + optional_component: Option>>, + world: &'rel_comp World, + ) -> Self + { + let relationship_comp = + ComponentRef::>::from_optional_component( + optional_component, + world, + ); + + let component_storage_lock = world + .data + .component_storage + .read_nonblock() + .expect("Failed to aquire read-only component storage lock"); + + Self { + relationship_comp, + // SAFETY: The component lock is not used for longer than the original + // lifetime + component_storage_lock: unsafe { component_storage_lock.upgrade_lifetime() }, + } + } +} + +impl<'rel_comp, Kind, ComponentT> Relation<'rel_comp, Kind, ComponentT> +where + ComponentT: Component, +{ + /// Returns the component of the target at the specified index. + /// + /// # Panics + /// Will panic if the entity does not exist in the archetype it belongs to. This + /// should hopefully never happend. + #[must_use] + pub fn get(&self, index: usize) -> Option> + { + let target = self.get_target(index)?; + + let archetype = self.component_storage_lock.get_entity_archetype(*target)?; + + let entity = archetype + .get_entity(*target) + .expect("Target entity is gone from archetype"); + + let component_index = + archetype.get_index_for_component(&ComponentId::of::())?; + + let component = ComponentRef::new( + entity + .get_component(component_index)? + .component + .read_nonblock() + .unwrap_or_else(|_| { + panic!( + "Failed to aquire read-write lock of component {}", + type_name::() + ) + }), + ); + + Some(component) + } + + /// Returns a reference to the target at the specified index. + #[must_use] + pub fn get_target(&self, index: usize) -> Option<&EntityUid> + { + match &self.relationship_comp.entity_uid { + SingleOrMultiple::Single(entity_uid) if index == 0 => Some(entity_uid), + SingleOrMultiple::Multiple(entity_uids) => entity_uids.get(index), + SingleOrMultiple::Single(_) => None, + } + } + + #[must_use] + pub fn target_count(&self) -> usize + { + match &self.relationship_comp.entity_uid { + SingleOrMultiple::Single(_) => 1, + SingleOrMultiple::Multiple(entity_uids) => entity_uids.len(), + } + } + + /// Returns a iterator of the components of the targets of this relationship. + #[must_use] + pub fn iter(&self) -> TargetComponentIter<'_, 'rel_comp, Kind, ComponentT> + { + TargetComponentIter { relation: self, index: 0 } + } +} + +impl<'relationship, 'rel_comp, Kind, ComponentT> IntoIterator + for &'relationship Relation<'rel_comp, Kind, ComponentT> +where + 'relationship: 'rel_comp, + ComponentT: Component, +{ + type IntoIter = TargetComponentIter<'relationship, 'rel_comp, Kind, ComponentT>; + type Item = ComponentRef<'rel_comp, ComponentT>; + + fn into_iter(self) -> Self::IntoIter + { + self.iter() + } +} + +/// Iterator of the components of the targets of a relationship. +pub struct TargetComponentIter<'relationship, 'rel_comp, Kind, ComponentT> +where + Kind: 'static, + ComponentT: Component, +{ + relation: &'relationship Relation<'rel_comp, Kind, ComponentT>, + index: usize, +} + +impl<'relationship, 'rel_comp, Kind, ComponentT> Iterator + for TargetComponentIter<'relationship, 'rel_comp, Kind, ComponentT> +where + 'relationship: 'rel_comp, + Kind: 'static, + ComponentT: Component, +{ + type Item = ComponentRef<'rel_comp, ComponentT>; + + fn next(&mut self) -> Option + { + let index = self.index; + + self.index += 1; + + self.relation.get(index) + } +} -- cgit v1.2.3-18-g5258