use std::iter;
use bevy::ecs::query::QueryIter;
use bevy::prelude::{Component, Entity, Mut, QueryState, Ref as BRef, Reflect, With, World};
use crate::custom_ref::Ref;
#[cfg(doc)]
use crate::ReflectQueryable;
macro_rules! impl_iter {
(
// module to define trait and structs internally used by the iter
mod $smod:ident;
// Item description and documentation
item: [$item_doc:literal, $item_doc_link:literal, $item_ty:ty];
// The iterable type, one returned by `iter` method on the state type
iter: pub struct $iter:ident(Box<dyn _>);
state: pub struct $state:ident(Box<dyn _>);
world_ty:$state_world_arg_ty:ty;
iter_body: $state_iter_body:expr;
impl QueryState [$($query_state_param_ty:tt)*];
impl [$($concrete_iter_params:tt)*] Iter for $concrete_iter_ty:ty
) => {
#[doc = concat!(
"An iterator over all [`", $item_doc, "`]($", $item_doc_link, ") in a `world`.
This iterates over entities in the `world` provided
to [`", stringify!($state), "`], for a [`ReflectQueryable`] component."
)]
pub struct $iter<'a, 'w: 'a, 's: 'a>(Box<dyn $smod::Iter<'w, 's> + 'a>);
impl<'a, 'w: 'a, 's: 'a> ExactSizeIterator for $iter<'a, 'w, 's> {
fn len(&self) -> usize { self.0.len() }
}
impl<'a, 'w: 'a, 's: 'a> Iterator for $iter<'a, 'w, 's> {
type Item = $item_ty;
fn next(&mut self) -> Option<Self::Item> { self.0.next() }
fn size_hint(&self) -> (usize, Option<usize>) { self.0.size_hint() }
}
#[doc = concat!(
"An erased [`QueryState`] to iterate over [`", $item_doc, "`](", $item_doc_link, ").
Use [`", stringify!($state), ".iter(world)`](Self::iter) to iterate over all
[`", $item_doc, "`](", $item_doc_link, ") with the underlying [`Component`]
of the [`ReflectQueryable`](crate::ReflectQueryable) this [`", stringify!($state), "`] was
created from."
)]
pub struct $state (pub(super) Box<dyn $smod::State>);
#[allow(clippy::redundant_closure_call)]
impl<C: Component + Reflect> $smod::State for QueryState <$($query_state_param_ty)*> {
fn iter<'a, 'w: 'a, 's: 'a>(
&'s mut self,
world: $state_world_arg_ty,
) -> $iter<'a, 'w, 's>
{
$iter(Box::new(($state_iter_body)(self, world)))
}
}
impl $state {
#[doc = concat!("Get an iterator over [`", $item_doc, "`](", $item_doc_link, ").")]
pub fn iter<'a, 'w: 'a, 's: 'a>(
&'s mut self,
world: $state_world_arg_ty,
) -> $iter<'a, 'w, 's>
{
self.0.iter(world)
}
}
mod $smod {
use super::*;
pub trait State {
fn iter<'a, 'w: 'a, 's: 'a>(
&'s mut self,
world: $state_world_arg_ty,
) -> $iter<'a, 'w, 's>;
}
pub trait Iter<'w, 's>: ExactSizeIterator<Item = $item_ty> {}
impl<'w, 's, $($concrete_iter_params)*> Iter<'w, 's> for $concrete_iter_ty {}
}
};
}
impl_iter! {
mod wrapper;
item: ["&dyn Reflect", "Reflect", &'w dyn Reflect];
iter: pub struct QuerydynIter(Box<dyn _>);
state: pub struct Querydyn(Box<dyn _>);
world_ty: &'w World;
iter_body: |query: &'s mut QueryState<_,_>, world| query.iter(world).map(C::as_reflect);
impl QueryState[&'static C, ()];
impl[ C: Component + Reflect, F: Fn(&C) -> &dyn Reflect ] Iter
for iter::Map<QueryIter<'w, 's, &'static C, ()>, F>
}
fn map_ref<C: Component + Reflect>(value: BRef<C>) -> Ref<dyn Reflect> {
Ref::map_from(value, C::as_reflect)
}
impl_iter! {
mod ref_wrapper;
item: ["Ref<dyn Reflect>", "Ref", Ref<'w, dyn Reflect>];
iter: pub struct RefQuerydynIter(Box<dyn _>);
state: pub struct RefQuerydyn(Box<dyn _>);
world_ty:&'w World;
iter_body: |query: &'s mut QueryState<_,_>, world| query.iter(world).map(map_ref);
impl QueryState[BRef<'static, C>, ()] ;
impl[ C: Component + Reflect, F: Fn(BRef<C>) -> Ref<dyn Reflect> ] Iter
for iter::Map<QueryIter<'w, 's, BRef<'static , C>, ()>, F>
}
impl_iter! {
mod entity_wrapper;
item: ["Entity", "Entity", Entity];
iter: pub struct EntityQuerydynIter(Box<dyn _>);
state: pub struct EntityQuerydyn(Box<dyn _>);
world_ty:&'w World;
iter_body: |query: &'s mut QueryState<_,_>, world| query.iter(world);
impl QueryState[Entity, With<C>] ;
impl[ C: Component] Iter for QueryIter<'w, 's, Entity, With<C>>
}
fn map_unchanged<C: Component + Reflect>(value: Mut<C>) -> Mut<dyn Reflect> {
value.map_unchanged(C::as_reflect_mut)
}
impl_iter! {
mod mut_wrapper;
item: ["Mut<dyn Reflect>", "Mut", Mut<'w, dyn Reflect>];
iter: pub struct MutQuerydynIter(Box<dyn _>);
state: pub struct MutQuerydyn(Box<dyn _>);
world_ty:&'w mut World;
iter_body: |query: &'s mut QueryState<_,_>, world| query.iter_mut(world).map(map_unchanged::<C>);
impl QueryState[&'static mut C, ()] ;
impl[C: Component + Reflect, F: Fn(Mut<C>) -> Mut<dyn Reflect>] Iter
for iter::Map<QueryIter<'w, 's, &'static mut C, ()>, F>
}