summaryrefslogtreecommitdiff
path: root/ecs/src/relationship.rs
diff options
context:
space:
mode:
authorHampusM <hampus@hampusmat.com>2024-11-03 21:12:57 +0100
committerHampusM <hampus@hampusmat.com>2024-11-03 21:12:57 +0100
commitcaef866b4e3f87fd6ae2dd5b979a1fe1a1f3e5f2 (patch)
treefa390998ff41b11bb0e60298a81f45619fbe4d69 /ecs/src/relationship.rs
parent373a0d53f31b838b3f650a37df39176a31a6c1c4 (diff)
feat(ecs): add read-only query iterating
Diffstat (limited to 'ecs/src/relationship.rs')
-rw-r--r--ecs/src/relationship.rs185
1 files changed, 169 insertions, 16 deletions
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<Kind, ComponentT>>,
}
-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<dyn Component>>,
>,
@@ -109,7 +111,7 @@ where
) -> Self
{
let relationship_comp =
- ComponentRefMut::<Relationship<Kind, ComponentT>>::from_optional_component(
+ ComponentRefMut::<Relationship<Kind, ComponentT>>::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<Value>
Single(Value),
Multiple(Vec<Value>),
}
+
+pub struct Relation<'rel_comp, Kind, ComponentT>
+where
+ Kind: 'static,
+ ComponentT: Component,
+{
+ component_storage_lock: ReadGuard<'static, ComponentStorage>,
+ relationship_comp: ComponentRef<'rel_comp, Relationship<Kind, ComponentT>>,
+}
+
+impl<'rel_comp, Kind, ComponentT> FromOptionalComponent<'rel_comp>
+ for Relation<'rel_comp, Kind, ComponentT>
+where
+ ComponentT: Component,
+{
+ fn from_optional_component(
+ optional_component: Option<ReadGuard<'rel_comp, Box<dyn Component>>>,
+ world: &'rel_comp World,
+ ) -> Self
+ {
+ let relationship_comp =
+ ComponentRef::<Relationship<Kind, ComponentT>>::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<ComponentRef<'_, ComponentT>>
+ {
+ 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::<ComponentT>())?;
+
+ 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::<ComponentT>()
+ )
+ }),
+ );
+
+ 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<Self::Item>
+ {
+ let index = self.index;
+
+ self.index += 1;
+
+ self.relation.get(index)
+ }
+}