From 9226356b7b54c4c5b036b6fee00bba376245c5f3 Mon Sep 17 00:00:00 2001 From: HampusM Date: Fri, 24 Jul 2026 22:32:21 +0200 Subject: feat(engine-ecs): add traversal query term --- engine-ecs/src/query/term.rs | 182 +++++++++++++++++++++++++++++++++---------- 1 file changed, 142 insertions(+), 40 deletions(-) (limited to 'engine-ecs/src/query/term.rs') diff --git a/engine-ecs/src/query/term.rs b/engine-ecs/src/query/term.rs index 04bca1d..1bcb3dd 100644 --- a/engine-ecs/src/query/term.rs +++ b/engine-ecs/src/query/term.rs @@ -1,20 +1,23 @@ use std::any::type_name; use std::marker::PhantomData; -use crate::World; use crate::component::{ Component, Handle as ComponentHandle, HandleMut as ComponentHandleMut, }; -use crate::entity::Handle as EntityHandle; use crate::query::{ + SearchResult, Term, + TermMetadata, + TermTuple, TermsBuilder, TermsBuilderInterface, + Traversal, + TraversalKind, }; -use crate::tuple::Tuple; use crate::uid::With as WithUid; +use crate::World; pub struct With where @@ -23,26 +26,27 @@ where _pd: PhantomData, } -impl<'world, WithUidT> Term<'world> for With +impl<'query, WithUidT> Term<'query> for With where WithUidT: WithUid, { - type AddField = Fields; + type Fields = (); fn apply_to_terms_builder( terms_builder: &mut TermsBuilder, + _term_metadata: TermMetadata, ) { terms_builder.present([WithUidT::uid()]); } - fn add_field( - _entity_handle: &EntityHandle<'world>, - _world: &'world World, - fields: Fields, - ) -> Self::AddField + fn fields( + _world: &'query World, + _search_result: &SearchResult<'query, '_>, + _term_metadata: TermMetadata, + ) -> Self::Fields { - fields + () } } @@ -53,48 +57,50 @@ where _pd: PhantomData, } -impl<'world, WithUidT> Term<'world> for Without +impl<'query, WithUidT> Term<'query> for Without where WithUidT: WithUid, { - type AddField = Fields; + type Fields = (); fn apply_to_terms_builder( terms_builder: &mut TermsBuilder, + _term_metadata: TermMetadata, ) { terms_builder.absent([WithUidT::uid()]); } - fn add_field( - _entity_handle: &EntityHandle<'world>, - _world: &'world World, - fields: Fields, - ) -> Self::AddField + fn fields( + _world: &'query World, + _search_result: &SearchResult<'query, '_>, + _term_metadata: TermMetadata, + ) -> Self::Fields { - fields + () } } -impl<'world, ComponentT: Component> Term<'world> for Option<&ComponentT> +impl<'query, ComponentT: Component> Term<'query> for Option<&ComponentT> { - type AddField = - Fields::WithElementAtEnd>>; + type Fields = (Option>,); fn apply_to_terms_builder( _terms_builder: &mut TermsBuilder, + _term_metadata: TermMetadata, ) { } - fn add_field( - entity_handle: &EntityHandle<'world>, - _world: &'world World, - fields: Fields, - ) -> Self::AddField + fn fields( + _world: &'query World, + search_result: &SearchResult<'query, '_>, + _term_metadata: TermMetadata, + ) -> Self::Fields { let component = (|| { - let comp_ref = &entity_handle + let comp_ref = &search_result + .entity_handle .get_matching_components(ComponentT::id()) .next()?; @@ -109,33 +115,36 @@ impl<'world, ComponentT: Component> Term<'world> for Option<&ComponentT> } })(); - fields.with_elem(component) + (component,) } } -impl<'world, ComponentT: Component> Term<'world> for Option<&mut ComponentT> +impl<'query, ComponentT: Component> Term<'query> for Option<&mut ComponentT> { - type AddField = - Fields::WithElementAtEnd>>; + type Fields = (Option>,); fn apply_to_terms_builder( _terms_builder: &mut TermsBuilder, + _term_metadata: TermMetadata, ) { } - fn add_field( - entity_handle: &EntityHandle<'world>, - world: &'world World, - fields: Fields, - ) -> Self::AddField + fn fields( + world: &'query World, + search_result: &SearchResult<'query, '_>, + _term_metadata: TermMetadata, + ) -> Self::Fields { let component = (|| { - let comp_ref = &entity_handle + let comp_ref = &search_result + .entity_handle .get_matching_components(ComponentT::id()) .next()?; - match ComponentHandleMut::::from_entity_component_ref(comp_ref, world) { + match ComponentHandleMut::::from_entity_component_ref( + comp_ref, world, + ) { Ok(component) => Some(component), Err(err) => { panic!( @@ -146,6 +155,99 @@ impl<'world, ComponentT: Component> Term<'world> for Option<&mut ComponentT> } })(); - fields.with_elem(component) + (component,) + } +} + +pub struct Traverse +{ + _pd: PhantomData<(TermsT, Kind, Relation)>, +} + +impl<'query, TermsT, Kind, Relation> Term<'query> for Traverse +where + TermsT: TermTuple<'query>, + Kind: TraversalKindType, + Relation: Component, +{ + type Fields = TermsT::Fields; + + fn apply_to_terms_builder( + terms_builder: &mut TermsBuilder, + term_metadata: TermMetadata, + ) + { + terms_builder.traverse([Traversal { + kind: Kind::traversal_kind(), + relation: Relation::id(), + terms: |traversal| { + let mut terms_builder = TermsBuilder::default(); + + TermsT::apply_terms_to_builder( + &mut terms_builder, + traversal + .term_metadata + .level + .checked_add(1) + .expect("Too large term level. Would overflow"), + ); + + terms_builder.build() + }, + term_metadata, + }]); } + + fn fields( + world: &'query World, + search_result: &SearchResult<'query, '_>, + term_metadata: TermMetadata, + ) -> Self::Fields + { + let Some(traversal_result) = search_result + .traversal_results + .iter() + .find(|traversal_result| traversal_result.term_metadata == term_metadata) + else { + unreachable!(); + }; + + let Some(found_ent) = world.get_entity(traversal_result.found_ent) else { + unreachable!(); + }; + + TermsT::get_fields( + world, + &SearchResult { + entity_handle: found_ent, + traversal_results: search_result.traversal_results, + }, + term_metadata + .level + .checked_add(1) + .expect("Too large term level. Would overflow"), + ) + } +} + +pub trait TraversalKindType: sealed::Sealed +{ + fn traversal_kind() -> TraversalKind; +} + +pub struct TraverseUp; + +impl TraversalKindType for TraverseUp +{ + fn traversal_kind() -> TraversalKind + { + TraversalKind::Up + } +} + +impl sealed::Sealed for TraverseUp {} + +mod sealed +{ + pub trait Sealed {} } -- cgit v1.2.3-18-g5258