use core::marker::PhantomData;
use crate::{
component::{ComponentId, StorageType},
prelude::*,
};
use super::{FilteredAccess, QueryData, QueryFilter};
pub struct QueryBuilder<'w, D: QueryData = (), F: QueryFilter = ()> {
access: FilteredAccess,
world: &'w mut World,
or: bool,
first: bool,
_marker: PhantomData<(D, F)>,
}
impl<'w, D: QueryData, F: QueryFilter> QueryBuilder<'w, D, F> {
pub fn new(world: &'w mut World) -> Self {
let fetch_state = D::init_state(world);
let filter_state = F::init_state(world);
let mut access = FilteredAccess::default();
D::update_component_access(&fetch_state, &mut access);
let mut filter_access = FilteredAccess::default();
F::update_component_access(&filter_state, &mut filter_access);
access.extend(&filter_access);
Self {
access,
world,
or: false,
first: false,
_marker: PhantomData,
}
}
pub(super) fn is_dense(&self) -> bool {
let is_dense = |component_id| {
self.world()
.components()
.get_info(component_id)
.is_some_and(|info| info.storage_type() == StorageType::Table)
};
let Ok(component_accesses) = self.access.access().try_iter_component_access() else {
return false;
};
component_accesses
.map(|access| *access.index())
.all(is_dense)
&& !self.access.access().has_read_all_components()
&& self.access.with_filters().all(is_dense)
&& self.access.without_filters().all(is_dense)
}
pub fn world(&self) -> &World {
self.world
}
pub fn world_mut(&mut self) -> &mut World {
self.world
}
pub fn extend_access(&mut self, mut access: FilteredAccess) {
if self.or {
if self.first {
access.required.clear();
self.access.extend(&access);
self.first = false;
} else {
self.access.append_or(&access);
}
} else {
self.access.extend(&access);
}
}
pub fn data<T: QueryData>(&mut self) -> &mut Self {
let state = T::init_state(self.world);
let mut access = FilteredAccess::default();
T::update_component_access(&state, &mut access);
self.extend_access(access);
self
}
pub fn filter<T: QueryFilter>(&mut self) -> &mut Self {
let state = T::init_state(self.world);
let mut access = FilteredAccess::default();
T::update_component_access(&state, &mut access);
self.extend_access(access);
self
}
pub fn with<T: Component>(&mut self) -> &mut Self {
self.filter::<With<T>>();
self
}
pub fn with_id(&mut self, id: ComponentId) -> &mut Self {
let mut access = FilteredAccess::default();
access.and_with(id);
self.extend_access(access);
self
}
pub fn without<T: Component>(&mut self) -> &mut Self {
self.filter::<Without<T>>();
self
}
pub fn without_id(&mut self, id: ComponentId) -> &mut Self {
let mut access = FilteredAccess::default();
access.and_without(id);
self.extend_access(access);
self
}
pub fn ref_id(&mut self, id: ComponentId) -> &mut Self {
self.with_id(id);
self.access.add_component_read(id);
self
}
pub fn mut_id(&mut self, id: ComponentId) -> &mut Self {
self.with_id(id);
self.access.add_component_write(id);
self
}
pub fn optional(&mut self, f: impl Fn(&mut QueryBuilder)) -> &mut Self {
let mut builder = QueryBuilder::new(self.world);
f(&mut builder);
self.access.extend_access(builder.access());
self
}
pub fn and(&mut self, f: impl Fn(&mut QueryBuilder)) -> &mut Self {
let mut builder = QueryBuilder::new(self.world);
f(&mut builder);
let access = builder.access().clone();
self.extend_access(access);
self
}
pub fn or(&mut self, f: impl Fn(&mut QueryBuilder)) -> &mut Self {
let mut builder = QueryBuilder::new(self.world);
builder.or = true;
builder.first = true;
f(&mut builder);
self.access.extend(builder.access());
self
}
pub fn access(&self) -> &FilteredAccess {
&self.access
}
pub fn transmute<NewD: QueryData>(&mut self) -> &mut QueryBuilder<'w, NewD> {
self.transmute_filtered::<NewD, ()>()
}
pub fn transmute_filtered<NewD: QueryData, NewF: QueryFilter>(
&mut self,
) -> &mut QueryBuilder<'w, NewD, NewF> {
let fetch_state = NewD::init_state(self.world);
let filter_state = NewF::init_state(self.world);
let mut access = FilteredAccess::default();
NewD::update_component_access(&fetch_state, &mut access);
NewF::update_component_access(&filter_state, &mut access);
self.extend_access(access);
unsafe { core::mem::transmute(self) }
}
pub fn build(&mut self) -> QueryState<D, F> {
QueryState::<D, F>::from_builder(self)
}
}
#[cfg(test)]
mod tests {
use crate::{
prelude::*,
world::{EntityMutExcept, EntityRefExcept, FilteredEntityMut, FilteredEntityRef},
};
use std::dbg;
#[derive(Component, PartialEq, Debug)]
struct A(usize);
#[derive(Component, PartialEq, Debug)]
struct B(usize);
#[derive(Component, PartialEq, Debug)]
struct C(usize);
#[test]
fn builder_with_without_static() {
let mut world = World::new();
let entity_a = world.spawn((A(0), B(0))).id();
let entity_b = world.spawn((A(0), C(0))).id();
let mut query_a = QueryBuilder::<Entity>::new(&mut world)
.with::<A>()
.without::<C>()
.build();
assert_eq!(entity_a, query_a.single(&world).unwrap());
let mut query_b = QueryBuilder::<Entity>::new(&mut world)
.with::<A>()
.without::<B>()
.build();
assert_eq!(entity_b, query_b.single(&world).unwrap());
}
#[test]
fn builder_with_without_dynamic() {
let mut world = World::new();
let entity_a = world.spawn((A(0), B(0))).id();
let entity_b = world.spawn((A(0), C(0))).id();
let component_id_a = world.register_component::<A>();
let component_id_b = world.register_component::<B>();
let component_id_c = world.register_component::<C>();
let mut query_a = QueryBuilder::<Entity>::new(&mut world)
.with_id(component_id_a)
.without_id(component_id_c)
.build();
assert_eq!(entity_a, query_a.single(&world).unwrap());
let mut query_b = QueryBuilder::<Entity>::new(&mut world)
.with_id(component_id_a)
.without_id(component_id_b)
.build();
assert_eq!(entity_b, query_b.single(&world).unwrap());
}
#[test]
fn builder_or() {
let mut world = World::new();
world.spawn((A(0), B(0)));
world.spawn(B(0));
world.spawn(C(0));
let mut query_a = QueryBuilder::<Entity>::new(&mut world)
.or(|builder| {
builder.with::<A>();
builder.with::<B>();
})
.build();
assert_eq!(2, query_a.iter(&world).count());
let mut query_b = QueryBuilder::<Entity>::new(&mut world)
.or(|builder| {
builder.with::<A>();
builder.without::<B>();
})
.build();
dbg!(&query_b.component_access);
assert_eq!(2, query_b.iter(&world).count());
let mut query_c = QueryBuilder::<Entity>::new(&mut world)
.or(|builder| {
builder.with::<A>();
builder.with::<B>();
builder.with::<C>();
})
.build();
assert_eq!(3, query_c.iter(&world).count());
}
#[test]
fn builder_transmute() {
let mut world = World::new();
world.spawn(A(0));
world.spawn((A(1), B(0)));
let mut query = QueryBuilder::<()>::new(&mut world)
.with::<B>()
.transmute::<&A>()
.build();
query.iter(&world).for_each(|a| assert_eq!(a.0, 1));
}
#[test]
fn builder_static_components() {
let mut world = World::new();
let entity = world.spawn((A(0), B(1))).id();
let mut query = QueryBuilder::<FilteredEntityRef>::new(&mut world)
.data::<&A>()
.data::<&B>()
.build();
let entity_ref = query.single(&world).unwrap();
assert_eq!(entity, entity_ref.id());
let a = entity_ref.get::<A>().unwrap();
let b = entity_ref.get::<B>().unwrap();
assert_eq!(0, a.0);
assert_eq!(1, b.0);
}
#[test]
fn builder_dynamic_components() {
let mut world = World::new();
let entity = world.spawn((A(0), B(1))).id();
let component_id_a = world.register_component::<A>();
let component_id_b = world.register_component::<B>();
let mut query = QueryBuilder::<FilteredEntityRef>::new(&mut world)
.ref_id(component_id_a)
.ref_id(component_id_b)
.build();
let entity_ref = query.single(&world).unwrap();
assert_eq!(entity, entity_ref.id());
let a = entity_ref.get_by_id(component_id_a).unwrap();
let b = entity_ref.get_by_id(component_id_b).unwrap();
unsafe {
assert_eq!(0, a.deref::<A>().0);
assert_eq!(1, b.deref::<B>().0);
}
}
#[test]
fn builder_provide_access() {
let mut world = World::new();
world.spawn((A(0), B(1)));
let mut query =
QueryBuilder::<(Entity, FilteredEntityRef, FilteredEntityMut)>::new(&mut world)
.data::<&mut A>()
.data::<&B>()
.build();
let (_entity, entity_ref_1, mut entity_ref_2) = query.single_mut(&mut world).unwrap();
assert!(entity_ref_1.get::<A>().is_some());
assert!(entity_ref_1.get::<B>().is_some());
assert!(entity_ref_2.get::<A>().is_some());
assert!(entity_ref_2.get_mut::<A>().is_none());
assert!(entity_ref_2.get::<B>().is_some());
assert!(entity_ref_2.get_mut::<B>().is_none());
let mut query =
QueryBuilder::<(Entity, FilteredEntityMut, FilteredEntityMut)>::new(&mut world)
.data::<&mut A>()
.data::<&B>()
.build();
let (_entity, mut entity_ref_1, mut entity_ref_2) = query.single_mut(&mut world).unwrap();
assert!(entity_ref_1.get::<A>().is_some());
assert!(entity_ref_1.get_mut::<A>().is_some());
assert!(entity_ref_1.get::<B>().is_some());
assert!(entity_ref_1.get_mut::<B>().is_none());
assert!(entity_ref_2.get::<A>().is_none());
assert!(entity_ref_2.get_mut::<A>().is_none());
assert!(entity_ref_2.get::<B>().is_some());
assert!(entity_ref_2.get_mut::<B>().is_none());
let mut query = QueryBuilder::<(FilteredEntityMut, &mut A, &B)>::new(&mut world)
.data::<&mut A>()
.data::<&mut B>()
.build();
let (mut entity_ref, _a, _b) = query.single_mut(&mut world).unwrap();
assert!(entity_ref.get::<A>().is_none());
assert!(entity_ref.get_mut::<A>().is_none());
assert!(entity_ref.get::<B>().is_some());
assert!(entity_ref.get_mut::<B>().is_none());
let mut query = QueryBuilder::<(FilteredEntityMut, &mut A, &B)>::new(&mut world)
.data::<EntityMut>()
.build();
let (mut entity_ref, _a, _b) = query.single_mut(&mut world).unwrap();
assert!(entity_ref.get::<A>().is_none());
assert!(entity_ref.get_mut::<A>().is_none());
assert!(entity_ref.get::<B>().is_some());
assert!(entity_ref.get_mut::<B>().is_none());
let mut query = QueryBuilder::<(FilteredEntityMut, EntityMutExcept<A>)>::new(&mut world)
.data::<EntityMut>()
.build();
let (mut entity_ref_1, _entity_ref_2) = query.single_mut(&mut world).unwrap();
assert!(entity_ref_1.get::<A>().is_some());
assert!(entity_ref_1.get_mut::<A>().is_some());
assert!(entity_ref_1.get::<B>().is_none());
assert!(entity_ref_1.get_mut::<B>().is_none());
let mut query = QueryBuilder::<(FilteredEntityMut, EntityRefExcept<A>)>::new(&mut world)
.data::<EntityMut>()
.build();
let (mut entity_ref_1, _entity_ref_2) = query.single_mut(&mut world).unwrap();
assert!(entity_ref_1.get::<A>().is_some());
assert!(entity_ref_1.get_mut::<A>().is_some());
assert!(entity_ref_1.get::<B>().is_some());
assert!(entity_ref_1.get_mut::<B>().is_none());
}
#[test]
fn builder_static_dense_dynamic_sparse() {
#[derive(Component)]
struct Dense;
#[derive(Component)]
#[component(storage = "SparseSet")]
struct Sparse;
let mut world = World::new();
world.spawn(Dense);
world.spawn((Dense, Sparse));
let mut query = QueryBuilder::<&Dense>::new(&mut world)
.with::<Sparse>()
.build();
let matched = query.iter(&world).count();
assert_eq!(matched, 1);
}
}