lyra-engine/crates/lyra-ecs/src/relation/relate_pair.rs

96 lines
2.6 KiB
Rust

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>;
}