From 8022e8998290b067b8aa0cb9cba8ba410826bdab Mon Sep 17 00:00:00 2001 From: HampusM Date: Thu, 21 May 2026 17:55:20 +0200 Subject: chore: rename ecs* crates to engine-ecs* --- engine-ecs/src/query/flexible.rs | 92 +++++++++++++++++++++++++++++++ engine-ecs/src/query/term.rs | 116 +++++++++++++++++++++++++++++++++++++++ 2 files changed, 208 insertions(+) create mode 100644 engine-ecs/src/query/flexible.rs create mode 100644 engine-ecs/src/query/term.rs (limited to 'engine-ecs/src/query') diff --git a/engine-ecs/src/query/flexible.rs b/engine-ecs/src/query/flexible.rs new file mode 100644 index 0000000..936ab82 --- /dev/null +++ b/engine-ecs/src/query/flexible.rs @@ -0,0 +1,92 @@ +//! Low-level querying. +use std::iter::{repeat_n, FlatMap, RepeatN, Zip}; + +use crate::component::storage::archetype::{Archetype, EntityIter}; +use crate::component::storage::{ArchetypeRefIter, ArchetypeSearchTerms}; +use crate::entity::Handle as EntityHandle; +use crate::query::Terms; +use crate::World; + +/// Low-level entity query structure. +#[derive(Debug)] +pub struct Query<'world, const MAX_TERM_CNT: usize> +{ + world: &'world World, + terms: Terms, +} + +impl<'world, const MAX_TERM_CNT: usize> Query<'world, MAX_TERM_CNT> +{ + /// Iterates over the entities matching this query. + #[must_use] + pub fn iter(&self) -> Iter<'_> + { + Iter { + iter: self + .world + .data + .component_storage + .search_archetypes(ArchetypeSearchTerms { + required_components: &self.terms.required_components, + excluded_components: &self.terms.excluded_components, + }) + .flat_map( + (|archetype| { + repeat_n(archetype, archetype.entity_cnt()) + .zip(archetype.entities()) + }) as ComponentIterMapFn, + ), + world: self.world, + } + } + + #[must_use] + pub fn world(&self) -> &'world World + { + self.world + } + + pub(crate) fn new(world: &'world World, terms: Terms) -> Self + { + Self { world, terms } + } +} + +impl<'query, const MAX_TERM_CNT: usize> IntoIterator for &'query Query<'_, MAX_TERM_CNT> +{ + type IntoIter = Iter<'query>; + type Item = EntityHandle<'query>; + + fn into_iter(self) -> Self::IntoIter + { + self.iter() + } +} + +pub struct Iter<'query> +{ + iter: QueryEntityIter<'query>, + world: &'query World, +} + +impl<'query> Iterator for Iter<'query> +{ + type Item = EntityHandle<'query>; + + fn next(&mut self) -> Option + { + let (archetype, entity) = self.iter.next()?; + + Some(EntityHandle::new(archetype, entity, self.world)) + } +} + +type ComponentIterMapFnOutput<'a> = Zip, EntityIter<'a>>; + +type ComponentIterMapFn = for<'a> fn(&'a Archetype) -> ComponentIterMapFnOutput<'a>; + +type QueryEntityIter<'query> = FlatMap< + ArchetypeRefIter<'query, 'query>, + ComponentIterMapFnOutput<'query>, + ComponentIterMapFn, +>; diff --git a/engine-ecs/src/query/term.rs b/engine-ecs/src/query/term.rs new file mode 100644 index 0000000..0683918 --- /dev/null +++ b/engine-ecs/src/query/term.rs @@ -0,0 +1,116 @@ +use std::any::type_name; +use std::marker::PhantomData; + +use crate::component::{ + Component, + Handle as ComponentHandle, + HandleMut as ComponentHandleMut, +}; +use crate::query::{ + TermWithField, + TermWithoutField, + TermsBuilder, + TermsBuilderInterface, +}; +use crate::uid::With as WithUid; + +pub struct With +where + WithUidT: WithUid, +{ + _pd: PhantomData, +} + +impl TermWithoutField for With +where + WithUidT: WithUid, +{ + fn apply_to_terms_builder( + terms_builder: &mut TermsBuilder, + ) + { + terms_builder.with::(); + } +} + +pub struct Without +where + WithUidT: WithUid, +{ + _pd: PhantomData, +} + +impl TermWithoutField for Without +where + WithUidT: WithUid, +{ + fn apply_to_terms_builder( + terms_builder: &mut TermsBuilder, + ) + { + terms_builder.without::(); + } +} + +impl TermWithField for Option<&ComponentT> +{ + type Field<'a> = Option>; + + fn apply_to_terms_builder( + _terms_builder: &mut TermsBuilder, + ) + { + } + + fn get_field<'world>( + entity_handle: &crate::entity::Handle<'world>, + _world: &'world crate::World, + ) -> Self::Field<'world> + { + Some( + ComponentHandle::<'world, ComponentT>::from_entity_component_ref( + &entity_handle + .get_matching_components(ComponentT::id()) + .next()?, + ) + .unwrap_or_else(|err| { + panic!( + "Creating handle to component {} failed: {err}", + type_name::() + ); + }), + ) + } +} + +impl TermWithField for Option<&mut ComponentT> +{ + type Field<'a> = Option>; + + fn apply_to_terms_builder( + _terms_builder: &mut TermsBuilder, + ) + { + } + + fn get_field<'world>( + entity_handle: &crate::entity::Handle<'world>, + world: &'world crate::World, + ) -> Self::Field<'world> + { + Some( + ComponentHandleMut::<'world, ComponentT>::from_entity_component_ref( + &entity_handle + .get_matching_components(ComponentT::id()) + .next()?, + world, + ) + .unwrap_or_else(|err| { + panic!( + "Creating handle to component {} failed: {err}", + type_name::() + ); + }), + ) + } +} -- cgit v1.2.3-18-g5258