use std::marker::PhantomData;
use slotmap::basic::Keys;
use crate::entity::EntityId;
use crate::world::World;
use super::fetch::WorldQuery;
use super::filter::QueryFilter;
pub struct ExtQueryMut<'w, T: 'static + Send + Sync, F: QueryFilter = ()> {
world: &'w mut World,
ids: Vec<EntityId>,
_marker: PhantomData<(T, F)>,
}
impl<'w, T: 'static + Send + Sync, F: QueryFilter> ExtQueryMut<'w, T, F> {
pub(crate) fn new(world: &'w mut World) -> Self {
let ids: Vec<EntityId> = world
.alive_keys()
.filter(|&id| {
world.ext_map::<T>().is_some_and(|m| m.contains_key(id)) && F::matches(world, id)
})
.collect();
Self {
world,
ids,
_marker: PhantomData,
}
}
#[must_use]
pub fn ids(&self) -> &[EntityId] {
&self.ids
}
#[must_use]
pub const fn count(&self) -> usize {
self.ids.len()
}
pub fn for_each_mut(&mut self, mut f: impl FnMut(EntityId, &mut T)) {
for &id in &self.ids {
if let Some(val) = self.world.get_ext_mut::<T>(id) {
f(id, val);
}
}
}
}
pub struct QueryBuilder<'w, Q: WorldQuery, F: QueryFilter = ()> {
world: &'w World,
_marker: PhantomData<(Q, F)>,
}
impl<'w, Q: WorldQuery, F: QueryFilter> QueryBuilder<'w, Q, F> {
pub(crate) const fn new(world: &'w World) -> Self {
Self {
world,
_marker: PhantomData,
}
}
#[must_use]
pub const fn with<T: 'static>(self) -> QueryBuilder<'w, Q, (F, super::filter::With<T>)>
where
(F, super::filter::With<T>): QueryFilter,
{
QueryBuilder::new(self.world)
}
#[must_use]
pub const fn without<T: 'static>(self) -> QueryBuilder<'w, Q, (F, super::filter::Without<T>)>
where
(F, super::filter::Without<T>): QueryFilter,
{
QueryBuilder::new(self.world)
}
#[must_use]
pub const fn ext_with<T: 'static + Send + Sync>(
self,
) -> QueryBuilder<'w, Q, (F, super::filter::ExtWith<T>)>
where
(F, super::filter::ExtWith<T>): QueryFilter,
{
QueryBuilder::new(self.world)
}
#[must_use]
pub const fn ext_without<T: 'static + Send + Sync>(
self,
) -> QueryBuilder<'w, Q, (F, super::filter::ExtWithout<T>)>
where
(F, super::filter::ExtWithout<T>): QueryFilter,
{
QueryBuilder::new(self.world)
}
#[must_use]
pub fn iter(self) -> QueryIter<'w, Q, F> {
QueryIter {
world: self.world,
keys: self.world.alive_keys(),
_marker: PhantomData,
}
}
#[must_use]
pub fn get(self, id: EntityId) -> Option<Q::Item<'w>> {
if !Q::contains(self.world, id) || !F::matches(self.world, id) {
return None;
}
Q::fetch(self.world, id)
}
}
pub struct QueryIter<'w, Q: WorldQuery, F: QueryFilter> {
world: &'w World,
keys: Keys<'w, EntityId, ()>,
_marker: PhantomData<(Q, F)>,
}
impl<'w, Q: WorldQuery, F: QueryFilter> Iterator for QueryIter<'w, Q, F> {
type Item = Q::Item<'w>;
fn next(&mut self) -> Option<Self::Item> {
loop {
let id = self.keys.next()?;
if !Q::contains(self.world, id) {
continue;
}
if !F::matches(self.world, id) {
continue;
}
if let Some(item) = Q::fetch(self.world, id) {
return Some(item);
}
}
}
}
impl<'w, Q: WorldQuery, F: QueryFilter> QueryIter<'w, Q, F> {
#[must_use]
pub fn count_matches(self) -> usize {
self.count()
}
pub fn any_match(mut self, predicate: impl FnMut(Q::Item<'w>) -> bool) -> bool {
self.any(predicate)
}
pub fn all_match(mut self, predicate: impl FnMut(Q::Item<'w>) -> bool) -> bool {
self.all(predicate)
}
pub fn find_match(
mut self,
predicate: impl FnMut(&Q::Item<'w>) -> bool,
) -> Option<Q::Item<'w>> {
self.find(predicate)
}
}