use std::{marker::PhantomData, ptr};
use unchecked_unwrap::UncheckedUnwrap;
use crate::{IntoSendStorage, IntoStorages, StorageRef, UnorderedData, storage::{FastIndexExt, HiddenFastIndex, ReadOnlyStorage}, sync::IndexGuard, utils::delete_lifetime_mut};
#[cfg(feature = "parallel_iter")]
use crate::entity::{Entities, EntitiesStorage};
use super::{OptionStorage, OptionStorageMut};
pub trait Filter<'f> {
type Lifetimed;
}
pub trait FilterFrom<T>{
fn filter_from(t: T) -> Self;
}
#[doc(hidden)]
pub struct FilterStorage<'a, Filter, Storage>{
ids: IndexGuard<'a>,
storages: Storage,
marker: PhantomData<Filter>
}
impl<'a, Filter, Storage> FilterStorage<'a, Filter, Storage>{
pub fn new(storages: Storage, ids: IndexGuard<'a>) -> FilterStorage<'a, Filter, Storage>{
FilterStorage{
ids,
storages,
marker: PhantomData,
}
}
}
#[allow(non_snake_case)]
impl<'a, F, S> FastIndexExt for FilterStorage<'a, F, S>
where
S: FastIndexExt,
{
type FastIndex = S::FastIndex;
type StaticTypeId = S::StaticTypeId;
fn fast_index(&self, guid: usize) -> Self::FastIndex {
self.storages.fast_index(guid)
}
}
#[allow(non_snake_case)]
impl<'a, 'r, F, S> StorageRef<'r> for FilterStorage<'a, F, S>
where
S: StorageRef<'r>,
F: Filter<'r>,
F::Lifetimed: FilterFrom<<S as StorageRef<'r>>::Component>,
{
type Data = F::Lifetimed;
type Component = F::Lifetimed;
unsafe fn get_fast_unchecked(&'r mut self, idx: Self::FastIndex) -> Self::Component {
F::Lifetimed::filter_from(self.storages.get_fast_unchecked(idx))
}
unsafe fn get_unchecked(&'r mut self, guid: usize) -> Self::Component {
F::Lifetimed::filter_from(self.storages.get_unchecked(guid))
}
fn contains(&self, guid: usize) -> bool{
self.storages.contains(guid)
}
}
unsafe impl<'a, F, S> ReadOnlyStorage for FilterStorage<'a, F, S>
where S: ReadOnlyStorage{}
impl<'a, 'r, F, S> IntoSendStorage<'r> for FilterStorage<'a, F, S>
where
S: IntoSendStorage<'r>,
F: Filter<'r>,
F::Lifetimed: FilterFrom<<S::SendStorage as StorageRef<'r>>::Component>
{
type SendStorage = FilterStorage<'a, F, S::SendStorage>;
fn into_send_storage(&'r mut self) -> Self::SendStorage {
FilterStorage {
ids: self.ids.clone(),
storages: self.storages.into_send_storage(),
marker: PhantomData
}
}
}
impl<'a, F, S> IntoStorages for FilterStorage<'a, F, S>
where S: IntoStorages
{
type Storages = S::Storages;
fn into_storages(self) -> Self::Storages {
self.storages.into_storages()
}
}
impl<'a, 'r, F, S> OptionStorage<'r> for FilterStorage<'a, F, S>
where
S: FastIndexExt + IntoSendStorage<'r> + 'r,
S::SendStorage: ReadOnlyStorage,
F: Filter<'r> + UnorderedData<'a> + 'r,
F::Lifetimed: FilterFrom<<S::SendStorage as StorageRef<'r>>::Component> + 'r,
{
type Iter = FilterIter<'r, F, S::SendStorage>;
fn iter(this: Option<&'r Self>) -> FilterIter<'r, F, S::SendStorage> {
let ptr_range = this
.map(|s| s.ids.as_ptr_range())
.unwrap_or(ptr::null() .. ptr::null());
let storages = this.map(|storage| {
let storage = storage as *const Self as *mut Self;
unsafe{ (*storage).into_send_storage() }
});
FilterIter{
ptr: ptr_range.start,
end: ptr_range.end,
storages,
}
}
}
impl<'a, 'r, F, S> OptionStorageMut<'r> for FilterStorage<'a, F, S>
where
S: FastIndexExt + IntoSendStorage<'r> + 'r,
F: Filter<'r> + UnorderedData<'a> + 'r,
F::Lifetimed: FilterFrom<<S::SendStorage as StorageRef<'r>>::Component> + 'r,
{
type IterMut = FilterIter<'r, F, S::SendStorage>;
fn iter_mut(this: Option<&'r mut Self>) -> FilterIter<'r, F, S::SendStorage> {
let (ptr, end) = this
.as_ref()
.map(|s| (s.ids.as_ptr(), unsafe{ s.ids.as_ptr().add(s.ids.len()) }))
.unwrap_or((ptr::null(), ptr::null()));
let storages = this.map(|storage| storage.into_send_storage() );
FilterIter{
ptr,
end,
storages,
}
}
}
#[doc(hidden)]
pub struct FilterIter<'a, Filter, Storage>{
ptr: *const HiddenFastIndex,
end: *const HiddenFastIndex,
storages: Option<FilterStorage<'a, Filter, Storage>>,
}
impl<'a, Filter, Storage> FilterIter<'a, Filter, Storage>
where
Storage: FastIndexExt
{
pub fn new(storages: Option<FilterStorage<'a, Filter, Storage>>) -> FilterIter<'a, Filter, Storage>{
let (ptr, end) = storages.as_ref()
.map(|storages| (storages.ids.as_ptr(), unsafe{ storages.ids.as_ptr().add(storages.ids.len()) }))
.unwrap_or((ptr::null(), ptr::null()));
FilterIter{
ptr,
end,
storages,
}
}
}
impl<'a, F, S> Iterator for FilterIter<'a, F, S>
where
S: StorageRef<'a> + 'a,
F: Filter<'a> + 'a,
F::Lifetimed: FilterFrom<<S as StorageRef<'a>>::Component>,
{
type Item = F::Lifetimed;
#[allow(non_snake_case)]
fn next(&mut self) -> Option<Self::Item>{
unsafe {
if self.ptr == self.end {
None
} else {
let ids = &*self.ptr;
let ids = ids.unchecked_downcast_ref();
self.ptr = self.ptr.offset(1);
let storage = delete_lifetime_mut(self.storages.as_mut().unchecked_unwrap());
Some(storage.get_fast_unchecked(*ids))
}
}
}
fn size_hint(&self) -> (usize, Option<usize>) {
let len = self.end as usize - self.ptr as usize;
(len, Some(len))
}
}
impl<'a, F, S> ExactSizeIterator for FilterIter<'a, F, S>
where
S: StorageRef<'a> + 'a,
F: Filter<'a> + 'a,
F::Lifetimed: FilterFrom<<S as StorageRef<'a>>::Component>,
{
fn len(&self) -> usize {
self.end as usize - self.ptr as usize
}
}
#[cfg(feature = "parallel_iter")]
#[doc(hidden)]
pub struct FilterParIter<'a, Storage>{
ids: IndexGuard<'a>,
storages: Storage,
}
#[cfg(feature = "parallel_iter")]
impl<'a, Storage> FilterParIter<'a, Storage>
where Storage: FastIndexExt
{
pub fn new<U: UnorderedData<'a>>(entities: &'a Entities, storages: Storage) -> FilterParIter<'a, Storage>{
let ids = entities.entities_for_mask(
U::query_mask(entities),
&storages
);
FilterParIter{
ids,
storages,
}
}
}
#[cfg(feature = "parallel_iter")]
impl<'a, S1> rayon::iter::ParallelIterator for FilterParIter<'a, S1>
where
S1: Send + Sync + StorageRef<'a> + 'a,
<S1 as StorageRef<'a>>::Component: Send
{
type Item = <S1 as StorageRef<'a>>::Component;
#[allow(non_snake_case)]
fn drive_unindexed<C>(mut self, consumer: C) -> C::Result
where C: ::rayon::iter::plumbing::UnindexedConsumer<<S1 as StorageRef<'a>>::Component>
{
struct SendUnsafeCell<S>(*mut S);
unsafe impl<S> Send for SendUnsafeCell<S>{}
unsafe impl<S> Sync for SendUnsafeCell<S>{}
let storage = SendUnsafeCell(&mut self.storages as *mut S1);
use rayon::iter::{IntoParallelRefIterator};
let par_it = self.ids.par_iter();
unsafe{
par_it.map(move |fast_ids| {
let fast_ids = fast_ids.unchecked_downcast_ref();
(*storage.0).get_fast_unchecked(*fast_ids)
}).drive_unindexed(consumer)
}
}
}