use alloc::{
boxed::Box,
collections::{btree_map, btree_set},
rc::Rc,
};
use bevy_platform::collections::HashSet;
use core::{
array,
fmt::{Debug, Formatter},
hash::{BuildHasher, Hash},
iter::{self, FusedIterator},
option, result,
};
use super::{Entity, UniqueEntityEquivalentSlice};
use bevy_platform::sync::Arc;
pub trait ContainsEntity {
fn entity(&self) -> Entity;
}
pub unsafe trait EntityEquivalent: ContainsEntity + Eq {}
impl ContainsEntity for Entity {
fn entity(&self) -> Entity {
*self
}
}
unsafe impl EntityEquivalent for Entity {}
impl<T: ContainsEntity> ContainsEntity for &T {
fn entity(&self) -> Entity {
(**self).entity()
}
}
unsafe impl<T: EntityEquivalent> EntityEquivalent for &T {}
impl<T: ContainsEntity> ContainsEntity for &mut T {
fn entity(&self) -> Entity {
(**self).entity()
}
}
unsafe impl<T: EntityEquivalent> EntityEquivalent for &mut T {}
impl<T: ContainsEntity> ContainsEntity for Box<T> {
fn entity(&self) -> Entity {
(**self).entity()
}
}
unsafe impl<T: EntityEquivalent> EntityEquivalent for Box<T> {}
impl<T: ContainsEntity> ContainsEntity for Rc<T> {
fn entity(&self) -> Entity {
(**self).entity()
}
}
unsafe impl<T: EntityEquivalent> EntityEquivalent for Rc<T> {}
impl<T: ContainsEntity> ContainsEntity for Arc<T> {
fn entity(&self) -> Entity {
(**self).entity()
}
}
unsafe impl<T: EntityEquivalent> EntityEquivalent for Arc<T> {}
pub trait EntitySet: IntoIterator<IntoIter: EntitySetIterator> {}
impl<T: IntoIterator<IntoIter: EntitySetIterator>> EntitySet for T {}
pub unsafe trait EntitySetIterator: Iterator<Item: EntityEquivalent> {
fn collect_set<B: FromEntitySetIterator<Self::Item>>(self) -> B
where
Self: Sized,
{
FromEntitySetIterator::from_entity_set_iter(self)
}
}
unsafe impl<K: EntityEquivalent, V> EntitySetIterator for btree_map::Keys<'_, K, V> {}
unsafe impl<K: EntityEquivalent, V> EntitySetIterator for btree_map::IntoKeys<K, V> {}
unsafe impl<T: EntityEquivalent> EntitySetIterator for btree_set::Range<'_, T> {}
unsafe impl<T: EntityEquivalent + Ord> EntitySetIterator for btree_set::Intersection<'_, T> {}
unsafe impl<T: EntityEquivalent + Ord> EntitySetIterator for btree_set::Union<'_, T> {}
unsafe impl<T: EntityEquivalent + Ord> EntitySetIterator for btree_set::Difference<'_, T> {}
unsafe impl<T: EntityEquivalent + Ord> EntitySetIterator for btree_set::SymmetricDifference<'_, T> {}
unsafe impl<T: EntityEquivalent> EntitySetIterator for btree_set::Iter<'_, T> {}
unsafe impl<T: EntityEquivalent> EntitySetIterator for btree_set::IntoIter<T> {}
unsafe impl<T: EntityEquivalent> EntitySetIterator for option::Iter<'_, T> {}
unsafe impl<T: EntityEquivalent> EntitySetIterator for option::IntoIter<T> {}
unsafe impl<T: EntityEquivalent> EntitySetIterator for result::Iter<'_, T> {}
unsafe impl<T: EntityEquivalent> EntitySetIterator for result::IntoIter<T> {}
unsafe impl<T: EntityEquivalent> EntitySetIterator for array::IntoIter<T, 1> {}
unsafe impl<T: EntityEquivalent> EntitySetIterator for array::IntoIter<T, 0> {}
unsafe impl<T: EntityEquivalent, F: FnOnce() -> T> EntitySetIterator for iter::OnceWith<F> {}
unsafe impl<T: EntityEquivalent> EntitySetIterator for iter::Once<T> {}
unsafe impl<T: EntityEquivalent> EntitySetIterator for iter::Empty<T> {}
unsafe impl<I: EntitySetIterator + ?Sized> EntitySetIterator for &mut I {}
unsafe impl<I: EntitySetIterator + ?Sized> EntitySetIterator for Box<I> {}
unsafe impl<'a, T: 'a + EntityEquivalent + Copy, I: EntitySetIterator<Item = &'a T>>
EntitySetIterator for iter::Copied<I>
{
}
unsafe impl<'a, T: 'a + EntityEquivalent + Clone, I: EntitySetIterator<Item = &'a T>>
EntitySetIterator for iter::Cloned<I>
{
}
unsafe impl<I: EntitySetIterator, P: FnMut(&<I as Iterator>::Item) -> bool> EntitySetIterator
for iter::Filter<I, P>
{
}
unsafe impl<I: EntitySetIterator> EntitySetIterator for iter::Fuse<I> {}
unsafe impl<I: EntitySetIterator, F: FnMut(&<I as Iterator>::Item)> EntitySetIterator
for iter::Inspect<I, F>
{
}
unsafe impl<I: DoubleEndedIterator + EntitySetIterator> EntitySetIterator for iter::Rev<I> {}
unsafe impl<I: EntitySetIterator> EntitySetIterator for iter::Skip<I> {}
unsafe impl<I: EntitySetIterator, P: FnMut(&<I as Iterator>::Item) -> bool> EntitySetIterator
for iter::SkipWhile<I, P>
{
}
unsafe impl<I: EntitySetIterator> EntitySetIterator for iter::Take<I> {}
unsafe impl<I: EntitySetIterator, P: FnMut(&<I as Iterator>::Item) -> bool> EntitySetIterator
for iter::TakeWhile<I, P>
{
}
unsafe impl<I: EntitySetIterator> EntitySetIterator for iter::StepBy<I> {}
pub trait FromEntitySetIterator<A: EntityEquivalent>: FromIterator<A> {
fn from_entity_set_iter<T: EntitySet<Item = A>>(set_iter: T) -> Self;
}
impl<T: EntityEquivalent + Hash, S: BuildHasher + Default> FromEntitySetIterator<T>
for HashSet<T, S>
{
fn from_entity_set_iter<I: EntitySet<Item = T>>(set_iter: I) -> Self {
let iter = set_iter.into_iter();
let set = HashSet::<T, S>::with_capacity_and_hasher(iter.size_hint().0, S::default());
iter.fold(set, |mut set, e| {
unsafe {
set.insert_unique_unchecked(e);
}
set
})
}
}
pub struct UniqueEntityIter<I: Iterator<Item: EntityEquivalent>> {
iter: I,
}
impl<I: EntitySetIterator> UniqueEntityIter<I> {
pub fn from_entity_set_iterator<S>(iter: I) -> Self {
Self { iter }
}
}
impl<I: Iterator<Item: EntityEquivalent>> UniqueEntityIter<I> {
pub unsafe fn from_iterator_unchecked(iter: I) -> Self {
Self { iter }
}
pub fn into_inner(self) -> I {
self.iter
}
pub fn as_inner(&self) -> &I {
&self.iter
}
pub unsafe fn as_mut_inner(&mut self) -> &mut I {
&mut self.iter
}
}
impl<I: Iterator<Item: EntityEquivalent>> Iterator for UniqueEntityIter<I> {
type Item = I::Item;
fn next(&mut self) -> Option<Self::Item> {
self.iter.next()
}
fn size_hint(&self) -> (usize, Option<usize>) {
self.iter.size_hint()
}
}
impl<I: ExactSizeIterator<Item: EntityEquivalent>> ExactSizeIterator for UniqueEntityIter<I> {}
impl<I: DoubleEndedIterator<Item: EntityEquivalent>> DoubleEndedIterator for UniqueEntityIter<I> {
fn next_back(&mut self) -> Option<Self::Item> {
self.iter.next_back()
}
}
impl<I: FusedIterator<Item: EntityEquivalent>> FusedIterator for UniqueEntityIter<I> {}
unsafe impl<I: Iterator<Item: EntityEquivalent>> EntitySetIterator for UniqueEntityIter<I> {}
impl<T, I: Iterator<Item: EntityEquivalent> + AsRef<[T]>> AsRef<[T]> for UniqueEntityIter<I> {
fn as_ref(&self) -> &[T] {
self.iter.as_ref()
}
}
impl<T: EntityEquivalent, I: Iterator<Item: EntityEquivalent> + AsRef<[T]>>
AsRef<UniqueEntityEquivalentSlice<T>> for UniqueEntityIter<I>
{
fn as_ref(&self) -> &UniqueEntityEquivalentSlice<T> {
unsafe { UniqueEntityEquivalentSlice::from_slice_unchecked(self.iter.as_ref()) }
}
}
impl<T: EntityEquivalent, I: Iterator<Item: EntityEquivalent> + AsMut<[T]>>
AsMut<UniqueEntityEquivalentSlice<T>> for UniqueEntityIter<I>
{
fn as_mut(&mut self) -> &mut UniqueEntityEquivalentSlice<T> {
unsafe { UniqueEntityEquivalentSlice::from_slice_unchecked_mut(self.iter.as_mut()) }
}
}
impl<I: EntitySetIterator + Default> Default for UniqueEntityIter<I> {
fn default() -> Self {
Self {
iter: Default::default(),
}
}
}
impl<I: EntitySetIterator + Clone> Clone for UniqueEntityIter<I> {
fn clone(&self) -> Self {
Self {
iter: self.iter.clone(),
}
}
}
impl<I: Iterator<Item: EntityEquivalent> + Debug> Debug for UniqueEntityIter<I> {
fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
f.debug_struct("UniqueEntityIter")
.field("iter", &self.iter)
.finish()
}
}
#[cfg(test)]
mod tests {
use alloc::{vec, vec::Vec};
use crate::prelude::{Schedule, World};
use crate::component::Component;
use crate::entity::Entity;
use crate::query::{QueryState, With};
use crate::system::Query;
use crate::world::Mut;
use super::UniqueEntityIter;
#[derive(Component, Clone)]
pub struct Thing;
#[expect(
clippy::iter_skip_zero,
reason = "The `skip(0)` is used to ensure that the `Skip` iterator implements `EntitySet`, which is needed to pass the iterator as the `entities` parameter."
)]
#[test]
fn preserving_uniqueness() {
let mut world = World::new();
let mut query = QueryState::<&mut Thing>::new(&mut world);
let spawn_batch: Vec<Entity> = world.spawn_batch(vec![Thing; 1000]).collect();
let mut unique_entity_iter =
unsafe { UniqueEntityIter::from_iterator_unchecked(spawn_batch.iter()) };
let entity_set = unique_entity_iter
.by_ref()
.filter(|_| true)
.fuse()
.inspect(|_| ())
.rev()
.skip(0)
.skip_while(|_| false)
.take(1000)
.take_while(|_| true)
.step_by(2)
.cloned();
let _results: Vec<Mut<Thing>> =
query.iter_many_unique_mut(&mut world, entity_set).collect();
}
#[test]
fn nesting_queries() {
let mut world = World::new();
world.spawn_batch(vec![Thing; 1000]);
pub fn system(
mut thing_entities: Query<Entity, With<Thing>>,
mut things: Query<&mut Thing>,
) {
things.iter_many_unique(thing_entities.iter());
things.iter_many_unique_mut(thing_entities.iter_mut());
}
let mut schedule = Schedule::default();
schedule.add_systems(system);
schedule.run(&mut world);
}
}