use std::{any::TypeId, cell::Ref, marker::PhantomData}; use crate::{query::{AsQuery, Fetch, Query}, Archetype, ComponentColumn, Entity, World}; use super::{Relation, RelationOriginComponent}; pub struct FetchRelatePair<'a, T> { col: &'a ComponentColumn, arch: &'a Archetype, _phantom: PhantomData<&'a T> } impl<'a, R> Fetch<'a> for FetchRelatePair<'a, R> where R: Relation, { type Item = (Entity, Ref<'a, R>, Entity); fn dangling() -> Self { unreachable!() } unsafe fn get_item(&mut self, entity: crate::world::ArchetypeEntityId) -> Self::Item { let comp: Ref<RelationOriginComponent<R>> = self.col.get(entity.0 as usize); let rel_target = comp.target; let rel_origin = self.arch.entity_at_index(entity).unwrap(); let comp = Ref::map(comp, |r| &r.relation); (rel_origin, comp, rel_target) } } pub struct QueryRelatePair<R> { _marker: PhantomData<R>, } impl<R> Copy for QueryRelatePair<R> {} impl<R> Clone for QueryRelatePair<R> { fn clone(&self) -> Self { *self } } impl<R> QueryRelatePair<R> { pub fn new() -> Self { Self { _marker: PhantomData } } } impl<R> Query for QueryRelatePair<R> where R: Relation + 'static { type Item<'a> = (Entity, Ref<'a, R>, Entity); type Fetch<'a> = FetchRelatePair<'a, R>; fn new() -> Self { QueryRelatePair::<R>::new() } fn can_visit_archetype(&self, archetype: &crate::archetype::Archetype) -> bool { let tyid = crate::DynTypeId::Rust(TypeId::of::<RelationOriginComponent<R>>()); archetype.has_column(tyid) } unsafe fn fetch<'a>(&self, _world: &'a World, archetype: &'a crate::archetype::Archetype, tick: crate::Tick) -> Self::Fetch<'a> { let _ = tick; let col = archetype.get_column(TypeId::of::<RelationOriginComponent<R>>()) .expect("You ignored 'can_visit_archetype'!"); FetchRelatePair { col, arch: archetype, _phantom: PhantomData, } } } /// A query that fetches the origin, and target of a relation of type `R`. /// /// It provides it as a tuple in the following format: `(origin, relation, target)`. /// Similar to [`RelatesTo`](super::RelatesTo), you can use /// [`ViewState::relate_pair`](crate::relation::ViewState::relate_pair) to get a view that /// fetches the pair, or unlike [`RelatesTo`](super::RelatesTo), you can do the common /// procedure of using [`World::view`]. pub struct RelatePair<R: Relation> { _marker: PhantomData<R>, } impl<R: Relation> AsQuery for RelatePair<R> { type Query = QueryRelatePair<R>; }