use std::any::type_name; use std::marker::PhantomData; use crate::component::{ Component, Handle as ComponentHandle, HandleMut as ComponentHandleMut, }; use crate::query::{ SearchResult, Term, TermMetadata, TermTuple, TermsBuilder, TermsBuilderInterface, Traversal, TraversalKind, }; use crate::uid::With as WithUid; use crate::World; pub struct With where WithUidT: WithUid, { _pd: PhantomData, } impl<'query, WithUidT> Term<'query> for With where WithUidT: WithUid, { type Fields = (); fn apply_to_terms_builder( terms_builder: &mut TermsBuilder, _term_metadata: TermMetadata, ) { terms_builder.present([WithUidT::uid()]); } fn fields( _world: &'query World, _search_result: &SearchResult<'query, '_>, _term_metadata: TermMetadata, ) -> Self::Fields { () } } pub struct Without where WithUidT: WithUid, { _pd: PhantomData, } impl<'query, WithUidT> Term<'query> for Without where WithUidT: WithUid, { type Fields = (); fn apply_to_terms_builder( terms_builder: &mut TermsBuilder, _term_metadata: TermMetadata, ) { terms_builder.absent([WithUidT::uid()]); } fn fields( _world: &'query World, _search_result: &SearchResult<'query, '_>, _term_metadata: TermMetadata, ) -> Self::Fields { () } } impl<'query, ComponentT: Component> Term<'query> for Option<&ComponentT> { type Fields = (Option>,); fn apply_to_terms_builder( _terms_builder: &mut TermsBuilder, _term_metadata: TermMetadata, ) { } fn fields( _world: &'query World, search_result: &SearchResult<'query, '_>, _term_metadata: TermMetadata, ) -> Self::Fields { let component = (|| { let comp_ref = &search_result .entity_handle .get_matching_components(ComponentT::id()) .next()?; match ComponentHandle::::from_entity_component_ref(comp_ref) { Ok(component) => Some(component), Err(err) => { panic!( "Creating handle to component {} failed: {err}", type_name::() ); } } })(); (component,) } } impl<'query, ComponentT: Component> Term<'query> for Option<&mut ComponentT> { type Fields = (Option>,); fn apply_to_terms_builder( _terms_builder: &mut TermsBuilder, _term_metadata: TermMetadata, ) { } fn fields( world: &'query World, search_result: &SearchResult<'query, '_>, _term_metadata: TermMetadata, ) -> Self::Fields { let component = (|| { let comp_ref = &search_result .entity_handle .get_matching_components(ComponentT::id()) .next()?; match ComponentHandleMut::::from_entity_component_ref( comp_ref, world, ) { Ok(component) => Some(component), Err(err) => { panic!( "Creating mut handle to component {} failed: {err}", type_name::() ); } } })(); (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 {} }