use crate::{IntoSendStorage, entity::EntitiesStorage, storage::{FastIndexExt, ReadOnlyStorage}, sync::{ReadGuardRef, OrderedIndexGuard}};
use std::{marker, ops::Deref};
use crate::Component;
use crate::ComponentSend;
use crate::Bitmask;
use super::{OrderedData, SafeIter};
use crate::storage::{HierarchicalStorage, StorageRef, IntoHierarchicalIter};
use crate::utils::delete_lifetime;
use crate::storage::forest::ForestHierarchicalIter;
use crate::idtree;
use std::fmt::Debug;
pub struct ReadAndParent<'a, T>{
_marker: marker::PhantomData<&'a T>,
}
pub struct ParentStorageRead<'a, S, BS, T>{
storage: BS,
marker_t: marker::PhantomData<&'a T>,
marker_s: marker::PhantomData<S>
}
impl<'a, 'r, S, BS, T> FastIndexExt for ParentStorageRead<'a, S, BS, T>
where
S: HierarchicalStorage<'a,T> + 'a,
BS: Deref<Target = S>,
T: Component
{
type FastIndex = idtree::NodeId;
type StaticTypeId = T;
fn fast_index(&self, guid: usize) -> idtree::NodeId {
unsafe{ self.storage.ordered_fast_index(guid) }
}
}
impl<'a, 'r, S, BS, T> StorageRef<'r> for ParentStorageRead<'a, S, BS, T>
where
S: HierarchicalStorage<'a,T> + 'a,
BS: Deref<Target = S>,
T: Component
{
type Data = ReadAndParent<'a, T>;
type Component = (&'r T, Option<&'r T>);
unsafe fn get_fast_unchecked(&'r mut self, guid: idtree::NodeId) -> Self::Component {
let node = self.storage.fast_get_node(guid);
let parent = node.parent().map(|p| delete_lifetime(&p as &T) );
let node = delete_lifetime(&node as &T);
(&node, parent)
}
unsafe fn get_unchecked(&'r mut self, guid: usize) -> Self::Component {
let node = self.storage.get_node(guid);
let parent = node.parent().map(|p| delete_lifetime(&p as &T) );
let node = delete_lifetime(&node as &T);
(&node, parent)
}
fn contains(&self, guid: usize) -> bool {
self.storage.contains(guid)
}
}
impl<'a, 'r, S,T> IntoSendStorage<'r> for ParentStorageRead<'a, S, ReadGuardRef<'a, S>, T>
where
S: HierarchicalStorage<'a,T> + 'r,
T: Component
{
type SendStorage = ParentStorageRead<'a, S, &'r S, T>;
fn into_send_storage(&'r mut self) -> Self::SendStorage {
ParentStorageRead {
storage: &self.storage,
marker_s: marker::PhantomData,
marker_t: marker::PhantomData,
}
}
}
unsafe impl<'a, S, BS, T> ReadOnlyStorage for ParentStorageRead<'a, S, BS, T>{}
pub struct ReadAndParentIter<'a, T: Component>
where for<'b> <T as Component>::Storage: HierarchicalStorage<'b,T>,
{
it: Option<ForestHierarchicalIter<'a, T>>
}
impl<'a,T> Iterator for ReadAndParentIter<'a, T>
where T: Component + Debug,
for<'b> <T as Component>::Storage: HierarchicalStorage<'b,T>,
{
type Item = (&'a T, Option<&'a T>);
fn next(&mut self) -> Option<(&'a T, Option<&'a T>)>{
self.it.as_mut().and_then(|it| it.next().map(|n| {
let n_ref = unsafe{ delete_lifetime(&n as &T) };
let p = n.parent().map(|p| unsafe{ delete_lifetime(&p as &T) });
(n_ref, p)
}))
}
fn size_hint(&self) -> (usize, Option<usize>) {
self.it.as_ref().map(|it| it.size_hint()).unwrap_or((0, None))
}
}
unsafe impl<T> SafeIter<'_> for ReadAndParent<'_, T>{}
impl<'a, T: ComponentSend> OrderedData<'a> for ReadAndParent<'a,T>
where for<'b> <T as Component>::Storage: HierarchicalStorage<'b,T>,
for<'b> ReadGuardRef<'b, <T as Component>::Storage>: IntoHierarchicalIter<'b,T>
{
type Iter = ReadAndParentIter<'a,T>;
type Components = T;
type ComponentsRef = (&'a T, Option<&'a T>);
type Storage = ParentStorageRead<'a, <T as Component>::Storage, ReadGuardRef<'a, <T as Component>::Storage>, Self::Components>;
fn query_mask<E: EntitiesStorage>(entities: &E) -> Bitmask{
Bitmask::has(entities.component_mask::<T>())
}
fn into_iter<E: EntitiesStorage>(entities: &'a E) -> Self::Iter{
ReadAndParentIter{
it: entities.storage::<T>()
.map(|s| s.into_hierarchical_iter())
}
}
fn storage<E: EntitiesStorage>(entities: &'a E) -> Option<Self::Storage>{
Some(ParentStorageRead{
storage: entities.storage::<T>()?,
marker_s: marker::PhantomData,
marker_t: marker::PhantomData,
})
}
fn ordered_ids<S: FastIndexExt, E: EntitiesStorage>(entities: &'a E, query_mask: Bitmask, unordered_storage: &S) -> OrderedIndexGuard<'a>{
entities.ordered_entities_for::<T,_>(query_mask, unordered_storage)
}
}