use std::{
any::{Any, TypeId},
cell::{Ref, RefCell, RefMut},
marker::PhantomData, rc::Rc
};
use super::{Entities, Query};
impl<'a> Query<'a> {
pub fn query_fn<F, T: 'a>(&self, gen: F)
where
F: IntoFnQuery<'a, T>
{
gen.run(self.entities)
}
}
pub struct FnQuery<'a, T> {
entities: &'a Entities,
phantom: PhantomData<&'a T>,
}
impl<'a, T> FnQuery<'a, T> {
pub fn new(entities: &'a Entities) -> Self {
Self {
entities, phantom: PhantomData
}
}
}
pub trait IntoFnQuery<'a, Arguments> {
fn run(self, entities: &'a Entities);
}
pub trait QueryParameterType<'a> {
fn get(entities: &'a Entities) -> Self where Self: Sized;
}
impl<'a, T> QueryParameterType<'a> for FnQuery<'a, T>
where T: FnQueryContainedTupleType<'a>
{
fn get(entities: &'a Entities) -> Self where Self: Sized {
Self::new(entities)
}
}
pub trait FnQueryContainedTupleType<'a> {
type ReturnType;
fn map(entities: &'a Entities) -> Vec<Self::ReturnType>;
}
impl<'a, T> FnQueryContainedTupleType<'a> for T
where T: FnQueryContainedIndividualType<'a>
{
type ReturnType = T::ReturnType;
fn map(entities: &'a Entities) -> Vec<Self::ReturnType> {
T::map(entities)
}
}
impl<'a, T1, T2> FnQueryContainedTupleType<'a> for (T1, T2)
where
T1: FnQueryContainedIndividualType<'a>,
T2: FnQueryContainedIndividualType<'a>,
{
type ReturnType = (T1::ReturnType, T2::ReturnType);
fn map(entities: &'a Entities) -> Vec<Self::ReturnType> {
T1::map(entities).into_iter().zip(T2::map(entities)).collect()
}
}
impl<'a, T1, T2, T3> FnQueryContainedTupleType<'a> for (T1, T2, T3)
where
T1: FnQueryContainedIndividualType<'a>,
T2: FnQueryContainedIndividualType<'a>,
T3: FnQueryContainedIndividualType<'a>,
{
type ReturnType = (T1::ReturnType, T2::ReturnType, T3::ReturnType);
fn map(entities: &'a Entities) -> Vec<Self::ReturnType> {
T1::map(entities).into_iter()
.zip(T2::map(entities))
.zip(T3::map(entities))
.map(|((x, y), z)| (x, y, z))
.collect()
}
}
pub trait FnQueryContainedIndividualType<'a>
{
type ReturnType;
fn type_id_new() -> TypeId;
fn map(entities: &'a Entities) -> Vec<Self::ReturnType> {
let typeid = Self::type_id_new();
let selfmap = entities.bit_masks.get(&typeid).unwrap();
let all_components = entities.components.get(&typeid).unwrap();
let components = all_components.into_iter().enumerate()
.map(|(ind, c)| {
if (entities.map[ind] & selfmap == *selfmap) && c.is_some() {
Some(c.as_ref().unwrap())
} else {
None
}
})
.flatten()
.collect::<Vec<&Rc<RefCell<dyn Any>>>>();
components.into_iter().map(|component| {
Self::map_ref(&component.as_ref())
}).collect()
}
fn map_ref(reference: &'a RefCell<dyn Any>) -> Self::ReturnType;
}
impl<'a, T: Any> FnQueryContainedIndividualType<'a> for &T
{
type ReturnType = Ref<'a, T>;
fn type_id_new() -> TypeId {
TypeId::of::<T>()
}
fn map_ref(reference: &'a RefCell<dyn Any>) -> Self::ReturnType {
Ref::map(reference.borrow(), |any| {
any.downcast_ref::<T>().unwrap()
})
}
}
impl<'a, T: Any> FnQueryContainedIndividualType<'a> for &mut T
{
type ReturnType = RefMut<'a, T>;
fn type_id_new() -> TypeId {
TypeId::of::<T>()
}
fn map_ref(reference: &'a RefCell<dyn Any>) -> Self::ReturnType {
RefMut::map(reference.borrow_mut(), |any| {
any.downcast_mut::<T>().unwrap()
})
}
}
impl<'a, T, F> IntoFnQuery<'a, T> for F
where
T: QueryParameterType<'a>,
F: Fn(T),
{
fn run(self, entities: &'a Entities) {
(self)(QueryParameterType::get(entities))
}
}
impl<'a, T> FnQuery<'a, T>
where T: FnQueryContainedTupleType<'a>
{
pub fn iter(&self) -> FnQueryIterator<'a, T::ReturnType> {
FnQueryIterator {
components: T::map(self.entities),
phantom: PhantomData,
}
}
}
impl<'a, T> std::iter::IntoIterator for FnQuery<'a, T>
where T: FnQueryContainedTupleType<'a>
{
type Item = T::ReturnType;
type IntoIter = FnQueryIterator<'a, T::ReturnType>;
fn into_iter(self) -> Self::IntoIter {
FnQueryIterator {
components: T::map(self.entities),
phantom: PhantomData
}
}
}
pub struct FnQueryIterator<'a, T> {
components: Vec<T>,
phantom: PhantomData<&'a T>,
}
impl<'a, T> std::iter::Iterator for FnQueryIterator<'a, T> {
type Item = T;
fn next(&mut self) -> Option<Self::Item> {
self.components.pop()
}
}