use crate::borrow::RefIter;
use crate::borrow::RefIterMut;
use crate::borrow::RefMap;
use crate::borrow::RefMapMut;
use crate::borrow::RefMapMutSet;
use crate::borrow::RefMapSet;
use crate::borrow::TryRefIter;
use crate::borrow::TryRefIterMut;
use crate::entity::Entity;
use crate::filter::And;
use crate::filter::ArchetypeFilterData;
use crate::filter::ChunkFilterData;
use crate::filter::ChunksetFilterData;
use crate::filter::ComponentFilter;
use crate::filter::EntityFilter;
use crate::filter::EntityFilterTuple;
use crate::filter::Filter;
use crate::filter::FilterResult;
use crate::filter::Passthrough;
use crate::filter::TagFilter;
use crate::index::ChunkIndex;
use crate::index::{ArchetypeIndex, SetIndex};
#[cfg(feature = "par-iter")]
use crate::iterator::{FissileEnumerate, FissileIterator};
use crate::storage::ArchetypeData;
use crate::storage::Component;
use crate::storage::ComponentStorage;
use crate::storage::ComponentTypeId;
use crate::storage::Tag;
use crate::storage::TagTypeId;
use crate::subworld::{ComponentAccess, StorageAccessor};
use crate::{permission::Permissions, world::EntityStore};
use derivative::Derivative;
use std::any::TypeId;
use std::iter::Enumerate;
use std::iter::Repeat;
use std::iter::Take;
use std::marker::PhantomData;
use std::slice::Iter;
use std::slice::IterMut;
#[cfg(feature = "par-iter")]
use rayon::{
iter::plumbing::{bridge_unindexed, Folder, UnindexedConsumer, UnindexedProducer},
prelude::*,
};
pub trait View<'a>: Sized + Send + Sync + 'static {
type Iter: Iterator + 'a;
fn fetch(
archetype: &'a ArchetypeData,
chunk: &'a ComponentStorage,
chunk_index: ChunkIndex,
set_index: SetIndex,
) -> Self::Iter;
fn validate() -> bool;
fn validate_access(access: &ComponentAccess) -> bool;
fn reads<T: Component>() -> bool;
fn writes<T: Component>() -> bool;
fn requires_permissions() -> Permissions<ComponentTypeId>;
}
pub trait DefaultFilter {
type Filter: EntityFilter;
fn filter() -> Self::Filter;
}
#[doc(hidden)]
pub trait ReadOnly {}
#[doc(hidden)]
pub trait ViewElement {
type Component;
}
pub trait IntoQuery: DefaultFilter + for<'a> View<'a> {
fn query() -> Query<Self, <Self as DefaultFilter>::Filter>;
}
impl<T: DefaultFilter + for<'a> View<'a>> IntoQuery for T {
fn query() -> Query<Self, <Self as DefaultFilter>::Filter> {
if !Self::validate() {
panic!("invalid view, please ensure the view contains no duplicate component types");
}
Query {
view: PhantomData,
filter: Self::filter(),
}
}
}
#[derive(Derivative, Debug)]
#[derivative(Default(bound = ""))]
pub struct Read<T: Component>(PhantomData<T>);
impl<T: Component> ReadOnly for Read<T> {}
impl<T: Component> Copy for Read<T> {}
impl<T: Component> Clone for Read<T> {
fn clone(&self) -> Self { *self }
}
impl<'a, T: Component> DefaultFilter for Read<T> {
type Filter = EntityFilterTuple<ComponentFilter<T>, Passthrough, Passthrough>;
fn filter() -> Self::Filter { super::filter::filter_fns::component() }
}
impl<'a, T: Component> View<'a> for Read<T> {
type Iter = RefIter<'a, T, Iter<'a, T>>;
fn fetch(
_: &'a ArchetypeData,
chunk: &'a ComponentStorage,
_: ChunkIndex,
_: SetIndex,
) -> Self::Iter {
let (slice_borrow, slice) = unsafe {
chunk
.components(ComponentTypeId::of::<T>())
.unwrap_or_else(|| {
panic!(
"Component of type {:?} not found in chunk when fetching Read view",
std::any::type_name::<T>()
)
})
.data_slice::<T>()
.deconstruct()
};
RefIter::new(slice_borrow, slice.iter())
}
fn validate() -> bool { true }
fn reads<D: Component>() -> bool { TypeId::of::<T>() == TypeId::of::<D>() }
fn writes<D: Component>() -> bool { false }
fn validate_access(access: &ComponentAccess) -> bool {
access.allows_read(ComponentTypeId::of::<T>())
}
fn requires_permissions() -> Permissions<ComponentTypeId> {
let mut permissions = Permissions::new();
permissions.push_read(ComponentTypeId::of::<T>());
permissions
}
}
impl<T: Component> ViewElement for Read<T> {
type Component = T;
}
#[derive(Derivative, Debug)]
#[derivative(Default(bound = ""))]
pub struct TryRead<T: Component>(PhantomData<T>);
impl<T: Component> ReadOnly for TryRead<T> {}
impl<T: Component> Copy for TryRead<T> {}
impl<T: Component> Clone for TryRead<T> {
fn clone(&self) -> Self { *self }
}
impl<'a, T: Component> DefaultFilter for TryRead<T> {
type Filter = EntityFilterTuple<Passthrough, Passthrough, Passthrough>;
fn filter() -> Self::Filter { super::filter::filter_fns::passthrough() }
}
impl<'a, T: Component> View<'a> for TryRead<T> {
type Iter = TryRefIter<'a, T, Iter<'a, T>>;
fn fetch(
_: &'a ArchetypeData,
chunk: &'a ComponentStorage,
_: ChunkIndex,
_: SetIndex,
) -> Self::Iter {
unsafe {
chunk
.components(ComponentTypeId::of::<T>())
.map(|x| {
let (borrow, slice) = x.data_slice::<T>().deconstruct();
TryRefIter::found(borrow, slice.iter())
})
.unwrap_or_else(|| TryRefIter::missing(chunk.len()))
}
}
fn validate() -> bool { true }
fn reads<D: Component>() -> bool { TypeId::of::<T>() == TypeId::of::<D>() }
fn writes<D: Component>() -> bool { false }
fn requires_permissions() -> Permissions<ComponentTypeId> {
let mut permissions = Permissions::new();
permissions.push_read(ComponentTypeId::of::<T>());
permissions
}
fn validate_access(access: &ComponentAccess) -> bool {
access.allows_read(ComponentTypeId::of::<T>())
}
}
impl<T: Component> ViewElement for TryRead<T> {
type Component = T;
}
#[derive(Derivative, Debug)]
#[derivative(Default(bound = ""))]
pub struct Write<T: Component>(PhantomData<T>);
impl<T: Component> Copy for Write<T> {}
impl<T: Component> Clone for Write<T> {
fn clone(&self) -> Self { *self }
}
impl<'a, T: Component> DefaultFilter for Write<T> {
type Filter = EntityFilterTuple<ComponentFilter<T>, Passthrough, Passthrough>;
fn filter() -> Self::Filter { super::filter::filter_fns::component() }
}
impl<'a, T: Component> View<'a> for Write<T> {
type Iter = RefIterMut<'a, T, IterMut<'a, T>>;
#[inline]
fn fetch(
_: &'a ArchetypeData,
chunk: &'a ComponentStorage,
_: ChunkIndex,
_: SetIndex,
) -> Self::Iter {
let (slice_borrow, slice) = unsafe {
chunk
.components(ComponentTypeId::of::<T>())
.unwrap_or_else(|| {
panic!(
"Component of type {:?} not found in chunk when fetching Write view",
std::any::type_name::<T>()
)
})
.data_slice_mut::<T>()
.deconstruct()
};
RefIterMut::new(slice_borrow, slice.iter_mut())
}
#[inline]
fn validate() -> bool { true }
#[inline]
fn reads<D: Component>() -> bool { TypeId::of::<T>() == TypeId::of::<D>() }
#[inline]
fn writes<D: Component>() -> bool { TypeId::of::<T>() == TypeId::of::<D>() }
fn requires_permissions() -> Permissions<ComponentTypeId> {
let mut permissions = Permissions::new();
permissions.push(ComponentTypeId::of::<T>());
permissions
}
fn validate_access(access: &ComponentAccess) -> bool {
access.allows_write(ComponentTypeId::of::<T>())
}
}
impl<T: Component> ViewElement for Write<T> {
type Component = T;
}
#[derive(Derivative, Debug)]
#[derivative(Default(bound = ""))]
pub struct TryWrite<T: Component>(PhantomData<T>);
impl<T: Component> Copy for TryWrite<T> {}
impl<T: Component> Clone for TryWrite<T> {
fn clone(&self) -> Self { *self }
}
impl<'a, T: Component> DefaultFilter for TryWrite<T> {
type Filter = EntityFilterTuple<Passthrough, Passthrough, Passthrough>;
fn filter() -> Self::Filter { super::filter::filter_fns::passthrough() }
}
impl<'a, T: Component> View<'a> for TryWrite<T> {
type Iter = TryRefIterMut<'a, T, IterMut<'a, T>>;
fn fetch(
_: &'a ArchetypeData,
chunk: &'a ComponentStorage,
_: ChunkIndex,
_: SetIndex,
) -> Self::Iter {
unsafe {
chunk
.components(ComponentTypeId::of::<T>())
.map(|x| {
let (borrow, slice) = x.data_slice_mut::<T>().deconstruct();
TryRefIterMut::found(borrow, slice.iter_mut())
})
.unwrap_or_else(|| TryRefIterMut::missing(chunk.len()))
}
}
fn validate() -> bool { true }
#[inline]
fn reads<D: Component>() -> bool { TypeId::of::<T>() == TypeId::of::<D>() }
#[inline]
fn writes<D: Component>() -> bool { TypeId::of::<T>() == TypeId::of::<D>() }
fn requires_permissions() -> Permissions<ComponentTypeId> {
let mut permissions = Permissions::new();
permissions.push(ComponentTypeId::of::<T>());
permissions
}
fn validate_access(access: &ComponentAccess) -> bool {
access.allows_write(ComponentTypeId::of::<T>())
}
}
impl<T: Component> ViewElement for TryWrite<T> {
type Component = T;
}
#[derive(Debug)]
pub struct Tagged<T: Tag>(PhantomData<T>);
impl<T: Tag> ReadOnly for Tagged<T> {}
impl<T: Tag> Copy for Tagged<T> {}
impl<T: Tag> Clone for Tagged<T> {
fn clone(&self) -> Self { *self }
}
impl<'a, T: Tag> DefaultFilter for Tagged<T> {
type Filter = EntityFilterTuple<TagFilter<T>, Passthrough, Passthrough>;
fn filter() -> Self::Filter { super::filter::filter_fns::tag() }
}
impl<'a, T: Tag> View<'a> for Tagged<T> {
type Iter = Take<Repeat<&'a T>>;
#[inline]
fn fetch(
archetype: &'a ArchetypeData,
chunk: &'a ComponentStorage,
_: ChunkIndex,
SetIndex(set_index): SetIndex,
) -> Self::Iter {
let data = unsafe {
archetype
.tags()
.get(TagTypeId::of::<T>())
.unwrap_or_else(|| {
panic!(
"Component of type {:?} not found in archetype when fetching Tagged view",
std::any::type_name::<T>()
)
})
.data_slice::<T>()
.get_unchecked(set_index)
};
std::iter::repeat(data).take(chunk.len())
}
#[inline]
fn validate() -> bool { true }
#[inline]
fn reads<D: Component>() -> bool { false }
#[inline]
fn writes<D: Component>() -> bool { false }
fn requires_permissions() -> Permissions<ComponentTypeId> { Permissions::new() }
#[inline]
fn validate_access(_: &ComponentAccess) -> bool { true }
}
impl<T: Tag> ViewElement for Tagged<T> {
type Component = Tagged<T>;
}
macro_rules! impl_view_tuple {
( $( $ty: ident ),* ) => {
impl<$( $ty: ViewElement + DefaultFilter ),*> DefaultFilter for ($( $ty, )*) {
type Filter = EntityFilterTuple<
And<($( <$ty::Filter as EntityFilter>::ArchetypeFilter, )*)>,
And<($( <$ty::Filter as EntityFilter>::ChunksetFilter, )*)>,
And<($( <$ty::Filter as EntityFilter>::ChunkFilter, )*)>,
>;
fn filter() -> Self::Filter {
#![allow(non_snake_case)]
$( let $ty = $ty::filter().into_filters(); )*
EntityFilterTuple::new(
And { filters: ($( $ty.0, )*) },
And { filters: ($( $ty.1, )*) },
And { filters: ($( $ty.2, )*) },
)
}
}
impl<$( $ty: ReadOnly ),* > ReadOnly for ($( $ty, )*) {}
impl<$( $ty: ViewElement ),*> ViewElement for ($( $ty, )*) {
type Component = ($( $ty::Component, )*);
}
impl<'a, $( $ty: ViewElement + View<'a> ),* > View<'a> for ($( $ty, )*) {
type Iter = crate::zip::Zip<($( $ty::Iter, )*)>;
#[inline]
fn fetch(
archetype: &'a ArchetypeData,
chunk: &'a ComponentStorage,
chunk_index: ChunkIndex,
set_index: SetIndex,
) -> Self::Iter {
crate::zip::multizip(($( $ty::fetch(archetype.clone(), chunk.clone(), chunk_index, set_index), )*))
}
fn validate() -> bool {
let types = &[$( TypeId::of::<$ty::Component>() ),*];
for i in 0..types.len() {
for j in (i + 1)..types.len() {
if unsafe { types.get_unchecked(i) == types.get_unchecked(j) } {
return false;
}
}
}
true
}
fn validate_access(access: &ComponentAccess) -> bool {
$( $ty::validate_access(access) )&&*
}
fn reads<Data: Component>() -> bool {
$( $ty::reads::<Data>() )||*
}
fn writes<Data: Component>() -> bool {
$( $ty::writes::<Data>() )||*
}
fn requires_permissions() -> Permissions<ComponentTypeId> {
let mut permissions = Permissions::new();
$( permissions.add($ty::requires_permissions()); )*
permissions
}
}
};
}
impl_view_tuple!(A);
impl_view_tuple!(A, B);
impl_view_tuple!(A, B, C);
impl_view_tuple!(A, B, C, D);
impl_view_tuple!(A, B, C, D, E);
impl_view_tuple!(A, B, C, D, E, F);
impl_view_tuple!(A, B, C, D, E, F, G);
impl_view_tuple!(A, B, C, D, E, F, G, H);
impl_view_tuple!(A, B, C, D, E, F, G, H, I);
impl_view_tuple!(A, B, C, D, E, F, G, H, I, J);
impl_view_tuple!(A, B, C, D, E, F, G, H, I, J, K);
impl_view_tuple!(A, B, C, D, E, F, G, H, I, J, K, L);
pub struct Chunk<'a, V: for<'b> View<'b>> {
archetype: &'a ArchetypeData,
components: &'a ComponentStorage,
chunk_index: ChunkIndex,
set_index: SetIndex,
view: PhantomData<V>,
}
impl<'a, V: for<'b> View<'b>> Chunk<'a, V> {
pub fn new(archetype: &'a ArchetypeData, set_index: SetIndex, chunk_index: ChunkIndex) -> Self {
Self {
components: unsafe {
archetype
.chunkset_unchecked(set_index)
.chunk_unchecked(chunk_index)
},
archetype,
chunk_index,
set_index,
view: PhantomData,
}
}
#[inline]
pub fn entities(&self) -> &'a [Entity] { self.components.entities() }
#[inline]
pub fn iter_mut(&mut self) -> <V as View<'a>>::Iter {
V::fetch(
self.archetype,
self.components,
self.chunk_index,
self.set_index,
)
}
#[inline]
pub fn iter_entities_mut(&mut self) -> ZipEntities<'a, V> {
ZipEntities {
entities: self.entities(),
data: V::fetch(
self.archetype,
self.components,
self.chunk_index,
self.set_index,
),
index: 0,
view: PhantomData,
}
}
pub fn tag<T: Tag>(&self) -> Option<&T> {
self.archetype
.tags()
.get(TagTypeId::of::<T>())
.map(|tags| unsafe { tags.data_slice::<T>() })
.map(|slice| unsafe { slice.get_unchecked(*self.set_index) })
}
pub fn components<T: Component>(&self) -> Option<RefMap<'a, &[T]>> {
if !V::reads::<T>() {
panic!("data type not readable via this query");
}
self.components
.components(ComponentTypeId::of::<T>())
.map(|c| unsafe { c.data_slice::<T>() })
}
pub fn components_mut<T: Component>(&self) -> Option<RefMapMut<'a, &mut [T]>> {
if !V::writes::<T>() {
panic!("data type not writable via this query");
}
self.components
.components(ComponentTypeId::of::<T>())
.map(|c| unsafe { c.data_slice_mut::<T>() })
}
}
pub struct ZipEntities<'data, V: View<'data>> {
entities: &'data [Entity],
data: <V as View<'data>>::Iter,
index: usize,
view: PhantomData<V>,
}
impl<'data, V: View<'data>> Iterator for ZipEntities<'data, V> {
type Item = (Entity, <V::Iter as Iterator>::Item);
#[inline]
fn next(&mut self) -> Option<Self::Item> {
if let Some(data) = self.data.next() {
let i = self.index;
self.index += 1;
unsafe { Some((*self.entities.get_unchecked(i), data)) }
} else {
None
}
}
#[inline]
fn size_hint(&self) -> (usize, Option<usize>) {
let len = self.entities.len() - self.index;
(len, Some(len))
}
}
pub struct ChunkViewIter<'data, 'filter, V, FArch, FChunkset, FChunk>
where
V: for<'a> View<'a>,
FArch: Filter<ArchetypeFilterData<'data>>,
FChunkset: Filter<ChunksetFilterData<'data>>,
FChunk: Filter<ChunkFilterData<'data>>,
{
_view: PhantomData<V>,
storage: StorageAccessor<'data>,
arch_filter: &'filter FArch,
chunkset_filter: &'filter FChunkset,
chunk_filter: &'filter FChunk,
archetypes: Enumerate<FArch::Iter>,
set_frontier: Option<(&'data ArchetypeData, Take<Enumerate<FChunkset::Iter>>)>,
chunk_frontier: Option<(
&'data ArchetypeData,
SetIndex,
Take<Enumerate<FChunk::Iter>>,
)>,
}
impl<'data, 'filter, V, FArch, FChunkset, FChunk>
ChunkViewIter<'data, 'filter, V, FArch, FChunkset, FChunk>
where
V: for<'a> View<'a>,
FArch: Filter<ArchetypeFilterData<'data>>,
FChunkset: Filter<ChunksetFilterData<'data>>,
FChunk: Filter<ChunkFilterData<'data>>,
{
fn next_set(&mut self) -> Option<(&'data ArchetypeData, SetIndex)> {
loop {
if let Some((ref arch, ref mut chunks)) = self.set_frontier {
for (set_index, filter_data) in chunks {
if self.chunkset_filter.is_match(&filter_data).is_pass() {
return Some((arch, SetIndex(set_index)));
}
}
}
loop {
match self.archetypes.next() {
Some((arch_index, arch_data)) => {
if self.arch_filter.is_match(&arch_data).is_pass() {
if !self
.storage
.can_access_archetype(ArchetypeIndex(arch_index))
{
panic!(
"query attempted to access archetype unavailable via sub world"
);
}
self.set_frontier = {
let chunks = unsafe {
self.storage.inner().archetypes().get_unchecked(arch_index)
};
let data = ChunksetFilterData {
archetype_data: chunks,
};
Some((
chunks,
self.chunkset_filter
.collect(data)
.enumerate()
.take(chunks.len()),
))
};
break;
}
}
None => return None,
}
}
}
}
}
impl<'data, 'filter, V, FArch, FChunkset, FChunk> Iterator
for ChunkViewIter<'data, 'filter, V, FArch, FChunkset, FChunk>
where
V: for<'a> View<'a>,
FArch: Filter<ArchetypeFilterData<'data>>,
FChunkset: Filter<ChunksetFilterData<'data>>,
FChunk: Filter<ChunkFilterData<'data>>,
{
type Item = Chunk<'data, V>;
fn next(&mut self) -> Option<Self::Item> {
loop {
if let Some((ref arch, set_index, ref mut set)) = self.chunk_frontier {
for (chunk_index, filter_data) in set {
if self.chunk_filter.is_match(&filter_data).is_pass() {
return Some(Chunk::new(arch, set_index, ChunkIndex(chunk_index)));
}
}
}
if let Some((ref arch, set_index)) = self.next_set() {
let chunks = unsafe { arch.chunkset_unchecked(set_index) }.occupied();
self.chunk_frontier = Some((
arch,
set_index,
self.chunk_filter
.collect(ChunkFilterData { chunks })
.enumerate()
.take(chunks.len()),
))
} else {
return None;
}
}
}
}
pub struct ChunkDataIter<'data, V, I>
where
V: for<'a> View<'a>,
I: Iterator<Item = Chunk<'data, V>>,
{
iter: I,
frontier: Option<<V as View<'data>>::Iter>,
_view: PhantomData<V>,
}
impl<'data, V, I> Iterator for ChunkDataIter<'data, V, I>
where
V: for<'a> View<'a>,
I: Iterator<Item = Chunk<'data, V>>,
{
type Item = <<V as View<'data>>::Iter as Iterator>::Item;
#[inline(always)]
fn next(&mut self) -> Option<Self::Item> {
loop {
if let Some(ref mut inner) = self.frontier {
if let elt @ Some(_) = inner.next() {
return elt;
}
}
match self.iter.next() {
Some(mut inner) => self.frontier = Some(inner.iter_mut()),
None => return None,
}
}
}
}
pub struct ChunkEntityIter<'data, V, I>
where
V: for<'a> View<'a>,
I: Iterator<Item = Chunk<'data, V>>,
{
iter: I,
frontier: Option<ZipEntities<'data, V>>,
_view: PhantomData<V>,
}
impl<'data, 'query, V, I> Iterator for ChunkEntityIter<'data, V, I>
where
V: for<'a> View<'a>,
I: Iterator<Item = Chunk<'data, V>>,
{
type Item = (Entity, <<V as View<'data>>::Iter as Iterator>::Item);
#[inline]
fn next(&mut self) -> Option<Self::Item> {
loop {
if let Some(ref mut inner) = self.frontier {
if let elt @ Some(_) = inner.next() {
return elt;
}
}
match self.iter.next() {
Some(mut inner) => self.frontier = Some(inner.iter_entities_mut()),
None => return None,
}
}
}
}
#[derive(Derivative)]
#[derivative(Clone(bound = "F: Clone"))]
pub struct Query<V: for<'a> View<'a>, F: EntityFilter> {
view: PhantomData<V>,
pub filter: F,
}
impl<V, F> Query<V, F>
where
V: for<'a> View<'a>,
F: EntityFilter,
{
pub fn filter<T: EntityFilter>(self, filter: T) -> Query<V, <F as std::ops::BitAnd<T>>::Output>
where
F: std::ops::BitAnd<T>,
<F as std::ops::BitAnd<T>>::Output: EntityFilter,
{
Query {
view: self.view,
filter: self.filter & filter,
}
}
pub unsafe fn iter_chunks_unchecked<'a, 'data, T: EntityStore>(
&'a self,
world: &'data T,
) -> ChunkViewIter<'data, 'a, V, F::ArchetypeFilter, F::ChunksetFilter, F::ChunkFilter> {
self.filter.init();
let (arch_filter, chunkset_filter, chunk_filter) = self.filter.filters();
let storage = world.get_component_storage::<V>().unwrap();
let archetypes = arch_filter
.collect(ArchetypeFilterData {
component_types: storage.inner().component_types(),
tag_types: storage.inner().tag_types(),
})
.enumerate();
ChunkViewIter {
storage,
arch_filter,
chunkset_filter,
chunk_filter,
archetypes,
set_frontier: None,
chunk_frontier: None,
_view: PhantomData,
}
}
pub fn iter_chunks<'a, 'data, T: EntityStore>(
&'a self,
world: &'data T,
) -> ChunkViewIter<'data, 'a, V, F::ArchetypeFilter, F::ChunksetFilter, F::ChunkFilter>
where
V: ReadOnly,
{
unsafe { self.iter_chunks_unchecked(world) }
}
pub fn iter_chunks_mut<'a, 'data, T: EntityStore>(
&'a self,
world: &'data mut T,
) -> ChunkViewIter<'data, 'a, V, F::ArchetypeFilter, F::ChunksetFilter, F::ChunkFilter> {
unsafe { self.iter_chunks_unchecked(world) }
}
pub unsafe fn iter_entities_unchecked<'a, 'data, T: EntityStore>(
&'a self,
world: &'data T,
) -> ChunkEntityIter<
'data,
V,
ChunkViewIter<'data, 'a, V, F::ArchetypeFilter, F::ChunksetFilter, F::ChunkFilter>,
> {
ChunkEntityIter {
iter: self.iter_chunks_unchecked(world),
frontier: None,
_view: PhantomData,
}
}
pub fn iter_entities<'a, 'data, T: EntityStore>(
&'a self,
world: &'data T,
) -> ChunkEntityIter<
'data,
V,
ChunkViewIter<'data, 'a, V, F::ArchetypeFilter, F::ChunksetFilter, F::ChunkFilter>,
>
where
V: ReadOnly,
{
unsafe { self.iter_entities_unchecked(world) }
}
pub fn iter_entities_mut<'a, 'data, T: EntityStore>(
&'a self,
world: &'data mut T,
) -> ChunkEntityIter<
'data,
V,
ChunkViewIter<'data, 'a, V, F::ArchetypeFilter, F::ChunksetFilter, F::ChunkFilter>,
> {
unsafe { self.iter_entities_unchecked(world) }
}
pub unsafe fn iter_unchecked<'a, 'data, T: EntityStore>(
&'a self,
world: &'data T,
) -> ChunkDataIter<
'data,
V,
ChunkViewIter<'data, 'a, V, F::ArchetypeFilter, F::ChunksetFilter, F::ChunkFilter>,
> {
ChunkDataIter {
iter: self.iter_chunks_unchecked(world),
frontier: None,
_view: PhantomData,
}
}
pub fn iter<'a, 'data, T: EntityStore>(
&'a self,
world: &'data T,
) -> ChunkDataIter<
'data,
V,
ChunkViewIter<'data, 'a, V, F::ArchetypeFilter, F::ChunksetFilter, F::ChunkFilter>,
>
where
V: ReadOnly,
{
unsafe { self.iter_unchecked(world) }
}
pub fn iter_mut<'a, 'data, T: EntityStore>(
&'a self,
world: &'data mut T,
) -> ChunkDataIter<
'data,
V,
ChunkViewIter<'data, 'a, V, F::ArchetypeFilter, F::ChunksetFilter, F::ChunkFilter>,
> {
unsafe { self.iter_unchecked(world) }
}
pub unsafe fn for_each_entities_unchecked<'a, 'data, T, W>(&'a self, world: &'data W, mut f: T)
where
T: Fn((Entity, <<V as View<'data>>::Iter as Iterator>::Item)),
W: EntityStore,
{
for mut chunk in self.iter_chunks_unchecked(world) {
chunk.iter_entities_mut().for_each(&mut f)
}
}
pub fn for_each_entities<'a, 'data, T, W>(&'a self, world: &'data W, f: T)
where
T: Fn((Entity, <<V as View<'data>>::Iter as Iterator>::Item)),
V: ReadOnly,
W: EntityStore,
{
unsafe { self.for_each_entities_unchecked(world, f) };
}
pub fn for_each_entities_mut<'a, 'data, T, W>(&'a self, world: &'data mut W, f: T)
where
T: Fn((Entity, <<V as View<'data>>::Iter as Iterator>::Item)),
W: EntityStore,
{
unsafe { self.for_each_entities_unchecked(world, f) };
}
pub unsafe fn for_each_unchecked<'a, 'data, T, W>(&'a self, world: &'data W, mut f: T)
where
T: Fn(<<V as View<'data>>::Iter as Iterator>::Item),
W: EntityStore,
{
for mut chunk in self.iter_chunks_unchecked(world) {
chunk.iter_mut().for_each(&mut f)
}
}
pub fn for_each<'a, 'data, T, W>(&'a self, world: &'data W, f: T)
where
T: Fn(<<V as View<'data>>::Iter as Iterator>::Item),
V: ReadOnly,
W: EntityStore,
{
unsafe { self.for_each_unchecked(world, f) };
}
pub fn for_each_mut<'a, 'data, T, W>(&'a self, world: &'data mut W, f: T)
where
T: Fn(<<V as View<'data>>::Iter as Iterator>::Item),
W: EntityStore,
{
unsafe { self.for_each_unchecked(world, f) };
}
pub fn components<'a, T: Component, W: EntityStore>(
&self,
world: &'a W,
) -> RefMapSet<'a, Vec<&'a T>> {
if !V::reads::<T>() {
panic!("data type not readable via this query");
}
let mut borrows = vec![];
let mut refs = vec![];
let storage = world.get_component_storage::<Read<T>>().unwrap().inner();
unsafe {
self.filter
.iter_archetype_indexes(storage)
.flat_map(|archetype_index| {
storage
.archetypes()
.get_unchecked(archetype_index.0)
.iter_data_slice::<T>()
})
.map(|x| x.deconstruct())
.for_each(|(borrow, slice)| {
borrows.push(borrow);
refs.extend(slice);
});
}
RefMapSet::new(borrows, refs)
}
pub fn components_mut<'a, T: Component, W: EntityStore>(
&self,
world: &'a mut W,
) -> RefMapMutSet<'a, Vec<&'a mut T>> {
if !V::writes::<T>() {
panic!("data type not writable via this query");
}
let mut borrows = vec![];
let mut refs = vec![];
let storage = world.get_component_storage::<Read<T>>().unwrap().inner();
unsafe {
self.filter
.iter_archetype_indexes(storage)
.flat_map(|archetype_index| {
storage
.archetypes()
.get_unchecked(archetype_index.0)
.iter_data_slice_unchecked_mut::<T>()
})
.map(|x| x.deconstruct())
.for_each(|(borrow, slice)| {
borrows.push(borrow);
refs.extend(slice);
});
}
RefMapMutSet::new(borrows, refs)
}
#[cfg(feature = "par-iter")]
pub unsafe fn par_iter_chunks_unchecked<'a, 'data, W>(
&'a self,
world: &'data W,
) -> ChunkViewParIter<'data, 'a, V, F::ArchetypeFilter, F::ChunksetFilter, F::ChunkFilter>
where
<F::ArchetypeFilter as Filter<ArchetypeFilterData<'data>>>::Iter: FissileIterator,
<F::ChunksetFilter as Filter<ChunksetFilterData<'data>>>::Iter: FissileIterator,
<F::ChunkFilter as Filter<ChunkFilterData<'data>>>::Iter: FissileIterator,
W: EntityStore,
{
self.filter.init();
let (arch_filter, chunkset_filter, chunk_filter) = self.filter.filters();
let storage = world.get_component_storage::<V>().unwrap();
let archetypes = FissileEnumerate::new(arch_filter.collect(ArchetypeFilterData {
component_types: storage.inner().component_types(),
tag_types: storage.inner().tag_types(),
}));
ChunkViewParIter {
storage,
arch_filter,
chunkset_filter,
chunk_filter,
archetypes,
set_frontier: None,
chunk_frontier: None,
_view: PhantomData,
}
}
#[cfg(feature = "par-iter")]
pub fn par_iter_chunks<'a, 'data, W>(
&'a self,
world: &'data W,
) -> ChunkViewParIter<'data, 'a, V, F::ArchetypeFilter, F::ChunksetFilter, F::ChunkFilter>
where
<F::ArchetypeFilter as Filter<ArchetypeFilterData<'data>>>::Iter: FissileIterator,
<F::ChunksetFilter as Filter<ChunksetFilterData<'data>>>::Iter: FissileIterator,
<F::ChunkFilter as Filter<ChunkFilterData<'data>>>::Iter: FissileIterator,
V: ReadOnly,
W: EntityStore,
{
unsafe { self.par_iter_chunks_unchecked(world) }
}
#[cfg(feature = "par-iter")]
pub fn par_iter_chunks_mut<'a, 'data, W>(
&'a self,
world: &'data mut W,
) -> ChunkViewParIter<'data, 'a, V, F::ArchetypeFilter, F::ChunksetFilter, F::ChunkFilter>
where
<F::ArchetypeFilter as Filter<ArchetypeFilterData<'data>>>::Iter: FissileIterator,
<F::ChunksetFilter as Filter<ChunksetFilterData<'data>>>::Iter: FissileIterator,
<F::ChunkFilter as Filter<ChunkFilterData<'data>>>::Iter: FissileIterator,
W: EntityStore,
{
unsafe { self.par_iter_chunks_unchecked(world) }
}
#[cfg(feature = "par-iter")]
pub unsafe fn par_entities_for_each_unchecked<'a, T, W>(&'a self, world: &'a W, f: T)
where
T: Fn((Entity, <<V as View<'a>>::Iter as Iterator>::Item)) + Send + Sync,
<F::ArchetypeFilter as Filter<ArchetypeFilterData<'a>>>::Iter: FissileIterator,
<F::ChunksetFilter as Filter<ChunksetFilterData<'a>>>::Iter: FissileIterator,
<F::ChunkFilter as Filter<ChunkFilterData<'a>>>::Iter: FissileIterator,
W: EntityStore,
{
self.par_for_each_chunk_unchecked(world, |mut chunk| {
for data in chunk.iter_entities_mut() {
f(data);
}
});
}
#[cfg(feature = "par-iter")]
pub fn par_entities_for_each<'a, T, W>(&'a self, world: &'a W, f: T)
where
T: Fn((Entity, <<V as View<'a>>::Iter as Iterator>::Item)) + Send + Sync,
<F::ArchetypeFilter as Filter<ArchetypeFilterData<'a>>>::Iter: FissileIterator,
<F::ChunksetFilter as Filter<ChunksetFilterData<'a>>>::Iter: FissileIterator,
<F::ChunkFilter as Filter<ChunkFilterData<'a>>>::Iter: FissileIterator,
V: ReadOnly,
W: EntityStore,
{
unsafe { self.par_entities_for_each_unchecked(world, f) };
}
#[cfg(feature = "par-iter")]
pub fn par_entities_for_each_mut<'a, T, W>(&'a self, world: &'a mut W, f: T)
where
T: Fn((Entity, <<V as View<'a>>::Iter as Iterator>::Item)) + Send + Sync,
<F::ArchetypeFilter as Filter<ArchetypeFilterData<'a>>>::Iter: FissileIterator,
<F::ChunksetFilter as Filter<ChunksetFilterData<'a>>>::Iter: FissileIterator,
<F::ChunkFilter as Filter<ChunkFilterData<'a>>>::Iter: FissileIterator,
W: EntityStore,
{
unsafe { self.par_entities_for_each_unchecked(world, f) };
}
#[cfg(feature = "par-iter")]
pub unsafe fn par_for_each_unchecked<'a, T, W>(&'a self, world: &'a W, f: T)
where
T: Fn(<<V as View<'a>>::Iter as Iterator>::Item) + Send + Sync,
<F::ArchetypeFilter as Filter<ArchetypeFilterData<'a>>>::Iter: FissileIterator,
<F::ChunksetFilter as Filter<ChunksetFilterData<'a>>>::Iter: FissileIterator,
<F::ChunkFilter as Filter<ChunkFilterData<'a>>>::Iter: FissileIterator,
W: EntityStore,
{
self.par_for_each_chunk_unchecked(world, |mut chunk| {
for data in chunk.iter_mut() {
f(data);
}
});
}
#[cfg(feature = "par-iter")]
pub fn par_for_each<'a, T, W>(&'a self, world: &'a W, f: T)
where
T: Fn(<<V as View<'a>>::Iter as Iterator>::Item) + Send + Sync,
<F::ArchetypeFilter as Filter<ArchetypeFilterData<'a>>>::Iter: FissileIterator,
<F::ChunksetFilter as Filter<ChunksetFilterData<'a>>>::Iter: FissileIterator,
<F::ChunkFilter as Filter<ChunkFilterData<'a>>>::Iter: FissileIterator,
V: ReadOnly,
W: EntityStore,
{
unsafe { self.par_for_each_unchecked(world, f) };
}
#[cfg(feature = "par-iter")]
pub fn par_for_each_mut<'a, T, W>(&'a self, world: &'a mut W, f: T)
where
T: Fn(<<V as View<'a>>::Iter as Iterator>::Item) + Send + Sync,
<F::ArchetypeFilter as Filter<ArchetypeFilterData<'a>>>::Iter: FissileIterator,
<F::ChunksetFilter as Filter<ChunksetFilterData<'a>>>::Iter: FissileIterator,
<F::ChunkFilter as Filter<ChunkFilterData<'a>>>::Iter: FissileIterator,
W: EntityStore,
{
unsafe { self.par_for_each_unchecked(world, f) };
}
#[cfg(feature = "par-iter")]
pub unsafe fn par_for_each_chunk_unchecked<'a, T, W>(&'a self, world: &'a W, f: T)
where
T: Fn(Chunk<'a, V>) + Send + Sync,
<F::ArchetypeFilter as Filter<ArchetypeFilterData<'a>>>::Iter: FissileIterator,
<F::ChunksetFilter as Filter<ChunksetFilterData<'a>>>::Iter: FissileIterator,
<F::ChunkFilter as Filter<ChunkFilterData<'a>>>::Iter: FissileIterator,
W: EntityStore,
{
let par_iter = self.par_iter_chunks_unchecked(world);
ParallelIterator::for_each(par_iter, |chunk| {
f(chunk);
});
}
#[cfg(feature = "par-iter")]
pub fn par_for_each_chunk<'a, T, W>(&'a self, world: &'a W, f: T)
where
T: Fn(Chunk<'a, V>) + Send + Sync,
<F::ArchetypeFilter as Filter<ArchetypeFilterData<'a>>>::Iter: FissileIterator,
<F::ChunksetFilter as Filter<ChunksetFilterData<'a>>>::Iter: FissileIterator,
<F::ChunkFilter as Filter<ChunkFilterData<'a>>>::Iter: FissileIterator,
V: ReadOnly,
W: EntityStore,
{
unsafe { self.par_for_each_chunk_unchecked(world, f) };
}
#[cfg(feature = "par-iter")]
pub fn par_for_each_chunk_mut<'a, T, W>(&'a self, world: &'a mut W, f: T)
where
T: Fn(Chunk<'a, V>) + Send + Sync,
<F::ArchetypeFilter as Filter<ArchetypeFilterData<'a>>>::Iter: FissileIterator,
<F::ChunksetFilter as Filter<ChunksetFilterData<'a>>>::Iter: FissileIterator,
<F::ChunkFilter as Filter<ChunkFilterData<'a>>>::Iter: FissileIterator,
W: EntityStore,
{
unsafe { self.par_for_each_chunk_unchecked(world, f) };
}
}
#[cfg(feature = "par-iter")]
pub struct ChunkViewParIter<'data, 'filter, V, FArch, FChunkset, FChunk>
where
V: for<'a> View<'a>,
FArch: Filter<ArchetypeFilterData<'data>>,
FChunkset: Filter<ChunksetFilterData<'data>>,
FChunk: Filter<ChunkFilterData<'data>>,
FArch::Iter: FissileIterator,
FChunkset::Iter: FissileIterator,
FChunk::Iter: FissileIterator,
{
_view: PhantomData<V>,
storage: StorageAccessor<'data>,
arch_filter: &'filter FArch,
chunkset_filter: &'filter FChunkset,
chunk_filter: &'filter FChunk,
archetypes: FissileEnumerate<FArch::Iter>,
set_frontier: Option<(
&'data ArchetypeData,
FissileEnumerate<FChunkset::Iter>,
usize,
)>,
chunk_frontier: Option<(
&'data ArchetypeData,
SetIndex,
FissileEnumerate<FChunk::Iter>,
usize,
)>,
}
#[cfg(feature = "par-iter")]
impl<'data, 'filter, V, FArch, FChunkset, FChunk>
ChunkViewParIter<'data, 'filter, V, FArch, FChunkset, FChunk>
where
V: for<'a> View<'a>,
FArch: Filter<ArchetypeFilterData<'data>>,
FChunkset: Filter<ChunksetFilterData<'data>>,
FChunk: Filter<ChunkFilterData<'data>>,
FArch::Iter: FissileIterator,
FChunkset::Iter: FissileIterator,
FChunk::Iter: FissileIterator,
{
fn next_set(&mut self) -> Option<(&'data ArchetypeData, SetIndex)> {
loop {
if let Some((ref arch, ref mut chunks, index_bound)) = self.set_frontier {
for (set_index, filter_data) in chunks {
if set_index < index_bound
&& self.chunkset_filter.is_match(&filter_data).is_pass()
{
return Some((arch, SetIndex(set_index)));
}
}
}
loop {
match self.archetypes.next() {
Some((arch_index, arch_data)) => {
if self.arch_filter.is_match(&arch_data).is_pass() {
if !self
.storage
.can_access_archetype(ArchetypeIndex(arch_index))
{
panic!(
"query attempted to access archetype unavailable via sub world"
);
}
self.set_frontier = {
let arch = unsafe {
self.storage.inner().archetypes().get_unchecked(arch_index)
};
let data = ChunksetFilterData {
archetype_data: arch,
};
Some((
arch,
FissileEnumerate::new(self.chunkset_filter.collect(data)),
arch.len(),
))
};
break;
}
}
None => return None,
}
}
}
}
}
#[cfg(feature = "par-iter")]
impl<'data, 'filter, V, FArch, FChunkset, FChunk> Iterator
for ChunkViewParIter<'data, 'filter, V, FArch, FChunkset, FChunk>
where
V: for<'a> View<'a>,
FArch: Filter<ArchetypeFilterData<'data>>,
FChunkset: Filter<ChunksetFilterData<'data>>,
FChunk: Filter<ChunkFilterData<'data>>,
FArch::Iter: FissileIterator,
FChunkset::Iter: FissileIterator,
FChunk::Iter: FissileIterator,
{
type Item = Chunk<'data, V>;
fn next(&mut self) -> Option<Self::Item> {
loop {
if let Some((ref arch, set_index, ref mut set, index_bound)) = self.chunk_frontier {
for (chunk_index, filter_data) in set {
if chunk_index < index_bound
&& self.chunk_filter.is_match(&filter_data).is_pass()
{
return Some(Chunk::new(arch, set_index, ChunkIndex(chunk_index)));
}
}
}
if let Some((ref arch, set_index)) = self.next_set() {
let chunks = unsafe { arch.chunkset_unchecked(set_index) }.occupied();
self.chunk_frontier = Some((
arch,
set_index,
FissileEnumerate::new(self.chunk_filter.collect(ChunkFilterData { chunks })),
chunks.len(),
))
} else {
return None;
}
}
}
}
#[cfg(feature = "par-iter")]
impl<'data, 'filter, V, FArch, FChunkset, FChunk> ParallelIterator
for ChunkViewParIter<'data, 'filter, V, FArch, FChunkset, FChunk>
where
V: for<'a> View<'a>,
FArch: Filter<ArchetypeFilterData<'data>>,
FChunkset: Filter<ChunksetFilterData<'data>>,
FChunk: Filter<ChunkFilterData<'data>>,
FArch::Iter: FissileIterator,
FChunkset::Iter: FissileIterator,
FChunk::Iter: FissileIterator,
{
type Item = Chunk<'data, V>;
fn drive_unindexed<C>(self, consumer: C) -> C::Result
where
C: UnindexedConsumer<Self::Item>,
{
bridge_unindexed(self, consumer)
}
}
#[cfg(feature = "par-iter")]
impl<'data, 'filter, V, FArch, FChunkset, FChunk> UnindexedProducer
for ChunkViewParIter<'data, 'filter, V, FArch, FChunkset, FChunk>
where
V: for<'a> View<'a>,
FArch: Filter<ArchetypeFilterData<'data>>,
FChunkset: Filter<ChunksetFilterData<'data>>,
FChunk: Filter<ChunkFilterData<'data>>,
FArch::Iter: FissileIterator,
FChunkset::Iter: FissileIterator,
FChunk::Iter: FissileIterator,
{
type Item = Chunk<'data, V>;
fn split(self) -> (Self, Option<Self>) {
let Self {
_view,
storage,
arch_filter,
chunkset_filter,
chunk_filter,
archetypes,
set_frontier,
chunk_frontier,
} = self;
let (left_archetypes, right_archetypes, arch_size) = archetypes.split();
let (left_set, right_set, set_size) = if let Some((data, iter, bound)) = set_frontier {
let (left_iter, right_iter, iter_size) = iter.split();
(
Some((data, left_iter, bound)),
Some((data, right_iter, bound)),
iter_size,
)
} else {
(None, None, 0)
};
let (left_chunk, right_chunk, chunk_size) =
if let Some((data, idx, iter, bound)) = chunk_frontier {
let (left_iter, right_iter, iter_size) = iter.split();
(
Some((data, idx, left_iter, bound)),
Some((data, idx, right_iter, bound)),
iter_size,
)
} else {
(None, None, 0)
};
let right_split = Self {
_view,
storage: storage.clone(),
arch_filter,
chunkset_filter,
chunk_filter,
archetypes: right_archetypes,
set_frontier: right_set,
chunk_frontier: right_chunk,
};
if arch_size + set_size + chunk_size == 0 {
(right_split, None)
} else {
(
Self {
_view,
storage,
arch_filter,
chunkset_filter,
chunk_filter,
archetypes: left_archetypes,
set_frontier: left_set,
chunk_frontier: left_chunk,
},
Some(right_split),
)
}
}
fn fold_with<F>(self, folder: F) -> F
where
F: Folder<Self::Item>,
{
folder.consume_iter(self)
}
}