use core::cmp::Ordering;
use core::fmt;
use core::hash::{Hash, Hasher};
use core::marker::PhantomData;
use core::ops::{Deref, DerefMut};
use core::ptr::NonNull;
use evenio_macros::all_tuples;
pub use evenio_macros::Query;
use crate::access::{Access, ComponentAccess};
use crate::archetype::{Archetype, ArchetypeRow};
use crate::component::{Component, ComponentIdx};
use crate::entity::EntityId;
use crate::handler::{HandlerConfig, InitError};
use crate::mutability::Mutable;
use crate::world::World;
pub unsafe trait Query {
type Item<'a>;
type ArchState: Send + Sync + fmt::Debug + 'static;
type State: fmt::Debug + 'static;
fn init(
world: &mut World,
config: &mut HandlerConfig,
) -> Result<(ComponentAccess, Self::State), InitError>;
fn new_state(world: &mut World) -> Self::State;
fn new_arch_state(arch: &Archetype, state: &mut Self::State) -> Option<Self::ArchState>;
unsafe fn get<'a>(state: &Self::ArchState, row: ArchetypeRow) -> Self::Item<'a>;
}
pub unsafe trait ReadOnlyQuery: Query {}
unsafe impl<C: Component> Query for &'_ C {
type Item<'a> = &'a C;
type ArchState = ColumnPtr<C>;
type State = ComponentIdx;
fn init(
world: &mut World,
config: &mut HandlerConfig,
) -> Result<(ComponentAccess, Self::State), InitError> {
let idx = Self::new_state(world);
let ca = ComponentAccess::var(idx, Access::Read);
config.referenced_components.insert(idx);
Ok((ca, idx))
}
fn new_state(world: &mut World) -> Self::State {
world.add_component::<C>().index()
}
fn new_arch_state(arch: &Archetype, state: &mut Self::State) -> Option<Self::ArchState> {
arch.column_of(*state).map(|c| ColumnPtr(c.data().cast()))
}
unsafe fn get<'a>(state: &Self::ArchState, row: ArchetypeRow) -> Self::Item<'a> {
&*state.0.as_ptr().cast_const().add(row.0 as usize)
}
}
unsafe impl<C: Component> ReadOnlyQuery for &'_ C {}
unsafe impl<C: Component<Mutability = Mutable>> Query for &'_ mut C {
type Item<'a> = &'a mut C;
type ArchState = ColumnPtr<C>;
type State = ComponentIdx;
fn init(
world: &mut World,
config: &mut HandlerConfig,
) -> Result<(ComponentAccess, Self::State), InitError> {
let idx = Self::new_state(world);
let ca = ComponentAccess::var(idx, Access::ReadWrite);
config.referenced_components.insert(idx);
Ok((ca, idx))
}
fn new_state(world: &mut World) -> Self::State {
world.add_component::<C>().index()
}
fn new_arch_state(arch: &Archetype, state: &mut Self::State) -> Option<Self::ArchState> {
<&C>::new_arch_state(arch, state)
}
unsafe fn get<'a>(state: &Self::ArchState, row: ArchetypeRow) -> Self::Item<'a> {
&mut *state.0.as_ptr().add(row.0 as usize)
}
}
macro_rules! impl_query_tuple {
($(($Q:ident, $q:ident)),*) => {
#[allow(unused_variables, clippy::unused_unit)]
unsafe impl<$($Q: Query),*> Query for ($($Q,)*) {
type Item<'a> = ($($Q::Item<'a>,)*);
type ArchState = ($($Q::ArchState,)*);
type State = ($($Q::State,)*);
#[allow(unused_mut)]
fn init(
world: &mut World,
config: &mut HandlerConfig
) -> Result<(ComponentAccess, Self::State), InitError> {
let mut ca = ComponentAccess::new_true();
$(
let (this_ca, $q) = $Q::init(world, config)?;
ca = ca.and(&this_ca);
)*
Ok((ca, ($($q,)*)))
}
fn new_state(world: &mut World) -> Self::State {
(
$(
$Q::new_state(world),
)*
)
}
fn new_arch_state(arch: &Archetype, ($($q,)*): &mut Self::State) -> Option<Self::ArchState> {
Some((
$(
$Q::new_arch_state(arch, $q)?,
)*
))
}
unsafe fn get<'a>(($($q,)*): &Self::ArchState, row: ArchetypeRow) -> Self::Item<'a> {
(
$(
$Q::get($q, row),
)*
)
}
}
unsafe impl<$($Q: ReadOnlyQuery),*> ReadOnlyQuery for ($($Q,)*) {}
}
}
all_tuples!(impl_query_tuple, 0, 12, Q, q);
unsafe impl<Q: Query> Query for Option<Q> {
type Item<'a> = Option<Q::Item<'a>>;
type ArchState = Option<Q::ArchState>;
type State = Q::State;
fn init(
world: &mut World,
config: &mut HandlerConfig,
) -> Result<(ComponentAccess, Self::State), InitError> {
let (ca, state) = Q::init(world, config)?;
Ok((ComponentAccess::new_true().or(&ca), state))
}
fn new_state(world: &mut World) -> Self::State {
Q::new_state(world)
}
fn new_arch_state(arch: &Archetype, state: &mut Self::State) -> Option<Self::ArchState> {
Some(Q::new_arch_state(arch, state))
}
unsafe fn get<'a>(state: &Self::ArchState, row: ArchetypeRow) -> Self::Item<'a> {
state.as_ref().map(|f| Q::get(f, row))
}
}
unsafe impl<Q: ReadOnlyQuery> ReadOnlyQuery for Option<Q> {}
#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)]
pub enum Or<L, R> {
Left(L),
Right(R),
Both(L, R),
}
impl<L, R> Or<L, R> {
pub fn map<F, G, M, S>(self, f: F, g: G) -> Or<M, S>
where
F: FnOnce(L) -> M,
G: FnOnce(R) -> S,
{
match self {
Or::Left(l) => Or::Left(f(l)),
Or::Right(r) => Or::Right(g(r)),
Or::Both(l, r) => Or::Both(f(l), g(r)),
}
}
pub const fn as_ref(&self) -> Or<&L, &R> {
match self {
Or::Left(l) => Or::Left(l),
Or::Right(r) => Or::Right(r),
Or::Both(l, r) => Or::Both(l, r),
}
}
pub fn as_mut(&mut self) -> Or<&mut L, &mut R> {
match self {
Or::Left(l) => Or::Left(l),
Or::Right(r) => Or::Right(r),
Or::Both(l, r) => Or::Both(l, r),
}
}
}
unsafe impl<L, R> Query for Or<L, R>
where
L: Query,
R: Query,
{
type Item<'a> = Or<L::Item<'a>, R::Item<'a>>;
type ArchState = Or<L::ArchState, R::ArchState>;
type State = (L::State, R::State);
fn init(
world: &mut World,
config: &mut HandlerConfig,
) -> Result<(ComponentAccess, Self::State), InitError> {
let (ca_lhs, state_lhs) = L::init(world, config)?;
let (ca_rhs, state_rhs) = R::init(world, config)?;
let ca_both = ca_lhs.and(&ca_rhs);
Ok((ca_lhs.or(&ca_rhs).or(&ca_both), (state_lhs, state_rhs)))
}
fn new_state(world: &mut World) -> Self::State {
(L::new_state(world), R::new_state(world))
}
fn new_arch_state(
arch: &Archetype,
(left_state, right_state): &mut Self::State,
) -> Option<Self::ArchState> {
match (
L::new_arch_state(arch, left_state),
R::new_arch_state(arch, right_state),
) {
(None, None) => None,
(None, Some(r)) => Some(Or::Right(r)),
(Some(l), None) => Some(Or::Left(l)),
(Some(l), Some(r)) => Some(Or::Both(l, r)),
}
}
unsafe fn get<'a>(state: &Self::ArchState, row: ArchetypeRow) -> Self::Item<'a> {
state.as_ref().map(|l| L::get(l, row), |r| R::get(r, row))
}
}
unsafe impl<L, R> ReadOnlyQuery for Or<L, R>
where
L: ReadOnlyQuery,
R: ReadOnlyQuery,
{
}
#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)]
pub enum Xor<L, R> {
Left(L),
Right(R),
}
impl<L, R> Xor<L, R> {
pub fn map<F, G, M, S>(self, f: F, g: G) -> Xor<M, S>
where
F: FnOnce(L) -> M,
G: FnOnce(R) -> S,
{
match self {
Xor::Left(l) => Xor::Left(f(l)),
Xor::Right(r) => Xor::Right(g(r)),
}
}
pub const fn as_ref(&self) -> Xor<&L, &R> {
match self {
Xor::Left(l) => Xor::Left(l),
Xor::Right(r) => Xor::Right(r),
}
}
pub fn as_mut(&mut self) -> Xor<&mut L, &mut R> {
match self {
Xor::Left(l) => Xor::Left(l),
Xor::Right(r) => Xor::Right(r),
}
}
}
unsafe impl<L, R> Query for Xor<L, R>
where
L: Query,
R: Query,
{
type Item<'a> = Xor<L::Item<'a>, R::Item<'a>>;
type ArchState = Xor<L::ArchState, R::ArchState>;
type State = (L::State, R::State);
fn init(
world: &mut World,
config: &mut HandlerConfig,
) -> Result<(ComponentAccess, Self::State), InitError> {
let (ca_lhs, state_lhs) = L::init(world, config)?;
let (ca_rhs, state_rhs) = R::init(world, config)?;
Ok((
ca_lhs.and(&ca_rhs.not()).or(&ca_rhs.and(&ca_lhs.not())),
(state_lhs, state_rhs),
))
}
fn new_state(world: &mut World) -> Self::State {
(L::new_state(world), R::new_state(world))
}
fn new_arch_state(
arch: &Archetype,
(left_state, right_state): &mut Self::State,
) -> Option<Self::ArchState> {
match (
L::new_arch_state(arch, left_state),
R::new_arch_state(arch, right_state),
) {
(None, None) => None,
(None, Some(r)) => Some(Xor::Right(r)),
(Some(l), None) => Some(Xor::Left(l)),
(Some(_), Some(_)) => None,
}
}
unsafe fn get<'a>(state: &Self::ArchState, row: ArchetypeRow) -> Self::Item<'a> {
state.as_ref().map(|l| L::get(l, row), |r| R::get(r, row))
}
}
unsafe impl<L, R> ReadOnlyQuery for Xor<L, R>
where
L: ReadOnlyQuery,
R: ReadOnlyQuery,
{
}
#[derive(Default)]
pub enum Not<Q: ?Sized> {
#[doc(hidden)]
__Ignore(crate::ignore::Ignore<Q>),
#[doc(hidden)]
#[default]
__Value,
}
mod not_value {
#[doc(hidden)]
pub use super::Not::__Value as Not;
}
pub use not_value::*;
impl<Q: ?Sized> Clone for Not<Q> {
fn clone(&self) -> Self {
*self
}
}
impl<Q: ?Sized> Copy for Not<Q> {}
impl<Q: ?Sized> fmt::Debug for Not<Q> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("Not").finish()
}
}
unsafe impl<Q: Query> Query for Not<Q> {
type Item<'a> = Self;
type ArchState = ();
type State = Q::State;
fn init(
world: &mut World,
config: &mut HandlerConfig,
) -> Result<(ComponentAccess, Self::State), InitError> {
let (ca, state) = Q::init(world, config)?;
Ok((ca.not(), state))
}
fn new_state(world: &mut World) -> Self::State {
Q::new_state(world)
}
fn new_arch_state(arch: &Archetype, state: &mut Self::State) -> Option<Self::ArchState> {
match Q::new_arch_state(arch, state) {
Some(_) => None,
None => Some(()),
}
}
unsafe fn get<'a>(_state: &Self::ArchState, _row: ArchetypeRow) -> Self::Item<'a> {
Not
}
}
unsafe impl<Q: Query> ReadOnlyQuery for Not<Q> {}
pub struct With<Q>(PhantomData<fn() -> Q>);
impl<Q> With<Q> {
pub const fn new() -> Self {
Self(PhantomData)
}
}
impl<Q> Clone for With<Q> {
fn clone(&self) -> Self {
*self
}
}
impl<Q> Copy for With<Q> {}
impl<Q> Default for With<Q> {
fn default() -> Self {
Self(Default::default())
}
}
impl<Q> fmt::Debug for With<Q> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_tuple("With").finish()
}
}
unsafe impl<Q: Query> Query for With<Q> {
type Item<'a> = Self;
type ArchState = ();
type State = Q::State;
fn init(
world: &mut World,
config: &mut HandlerConfig,
) -> Result<(ComponentAccess, Self::State), InitError> {
let (mut ca, state) = Q::init(world, config)?;
ca.clear_access();
Ok((ca, state))
}
fn new_state(world: &mut World) -> Self::State {
Q::new_state(world)
}
fn new_arch_state(arch: &Archetype, state: &mut Self::State) -> Option<Self::ArchState> {
Q::new_arch_state(arch, state).map(|_| ())
}
unsafe fn get<'a>(_state: &Self::ArchState, _row: ArchetypeRow) -> Self::Item<'a> {
With::new()
}
}
unsafe impl<Q: Query> ReadOnlyQuery for With<Q> {}
pub struct Has<Q> {
has: bool,
_marker: PhantomData<fn() -> Q>,
}
impl<Q> Has<Q> {
pub const fn new(has: bool) -> Self {
Self {
has,
_marker: PhantomData,
}
}
pub const fn get(self) -> bool {
self.has
}
}
impl<Q> Clone for Has<Q> {
fn clone(&self) -> Self {
*self
}
}
impl<Q> Copy for Has<Q> {}
impl<Q> Default for Has<Q> {
fn default() -> Self {
Self {
has: false,
_marker: PhantomData,
}
}
}
impl<Q> fmt::Debug for Has<Q> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_tuple("Has").field(&self.has).finish()
}
}
impl<Q> PartialEq for Has<Q> {
fn eq(&self, other: &Self) -> bool {
self.has == other.has
}
}
impl<Q> Eq for Has<Q> {}
impl<Q> PartialOrd for Has<Q> {
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
Some(self.cmp(other))
}
}
impl<Q> Ord for Has<Q> {
fn cmp(&self, other: &Self) -> Ordering {
self.has.cmp(&other.has)
}
}
impl<Q> Hash for Has<Q> {
fn hash<H: Hasher>(&self, state: &mut H) {
self.has.hash(state);
}
}
impl<Q> Deref for Has<Q> {
type Target = bool;
fn deref(&self) -> &Self::Target {
&self.has
}
}
impl<Q> DerefMut for Has<Q> {
fn deref_mut(&mut self) -> &mut Self::Target {
&mut self.has
}
}
unsafe impl<Q: Query> Query for Has<Q> {
type Item<'a> = Self;
type ArchState = bool;
type State = Q::State;
fn init(
world: &mut World,
config: &mut HandlerConfig,
) -> Result<(ComponentAccess, Self::State), InitError> {
let (_, state) = Q::init(world, config)?;
Ok((ComponentAccess::new_true(), state))
}
fn new_state(world: &mut World) -> Self::State {
Q::new_state(world)
}
fn new_arch_state(arch: &Archetype, state: &mut Self::State) -> Option<Self::ArchState> {
Some(Q::new_arch_state(arch, state).is_some())
}
unsafe fn get<'a>(state: &Self::ArchState, _row: ArchetypeRow) -> Self::Item<'a> {
Self::new(*state)
}
}
unsafe impl<Q: Query> ReadOnlyQuery for Has<Q> {}
unsafe impl Query for EntityId {
type Item<'a> = Self;
type ArchState = ColumnPtr<EntityId>;
type State = ();
fn init(
_world: &mut World,
_config: &mut HandlerConfig,
) -> Result<(ComponentAccess, Self::State), InitError> {
Ok((ComponentAccess::new_true(), ()))
}
fn new_state(_world: &mut World) -> Self::State {}
fn new_arch_state(arch: &Archetype, (): &mut Self::State) -> Option<Self::ArchState> {
Some(unsafe {
ColumnPtr(NonNull::new(arch.entity_ids().as_ptr().cast_mut()).unwrap_unchecked())
})
}
unsafe fn get<'a>(state: &Self::ArchState, row: ArchetypeRow) -> Self::Item<'a> {
*state.0.as_ptr().add(row.0 as usize)
}
}
unsafe impl ReadOnlyQuery for EntityId {}
unsafe impl<T: ?Sized> Query for PhantomData<T> {
type Item<'a> = Self;
type ArchState = ();
type State = ();
fn init(
_world: &mut World,
_config: &mut HandlerConfig,
) -> Result<(ComponentAccess, Self::State), InitError> {
Ok((ComponentAccess::new_true(), ()))
}
fn new_state(_world: &mut World) -> Self::State {}
fn new_arch_state(_arch: &Archetype, _state: &mut Self::State) -> Option<Self::ArchState> {
Some(())
}
unsafe fn get<'a>(_state: &Self::ArchState, _row: ArchetypeRow) -> Self::Item<'a> {
Self
}
}
unsafe impl<T: ?Sized> ReadOnlyQuery for PhantomData<T> {}
#[repr(transparent)]
pub struct ColumnPtr<T>(pub NonNull<T>);
impl<T> Clone for ColumnPtr<T> {
fn clone(&self) -> Self {
*self
}
}
impl<T> Copy for ColumnPtr<T> {}
impl<T> fmt::Debug for ColumnPtr<T> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_tuple("ColumnPtr").field(&self.0).finish()
}
}
unsafe impl<T> Send for ColumnPtr<T> {}
unsafe impl<T> Sync for ColumnPtr<T> {}
#[cfg(test)]
mod tests {
use super::*;
use crate::prelude::*;
#[derive(GlobalEvent)]
struct E;
macro_rules! check_access {
($name:ident, $succeed:expr, $Q:ty) => {
#[test]
fn $name() {
let mut world = World::new();
let res = world.try_add_handler(|_: Receiver<E>, _: Fetcher<$Q>| {});
assert_eq!(res.is_ok(), $succeed, "{res:?}");
}
};
}
#[derive(Component)]
struct A;
#[derive(Component)]
struct B;
#[derive(Component)]
struct C;
check_access!(t00, true, &mut A);
check_access!(t01, true, (&mut A, &mut B));
check_access!(t02, false, (&mut A, &mut A));
check_access!(t03, false, (&mut A, (&mut A,)));
check_access!(t04, false, (&mut A, &A));
check_access!(t05, true, (&A, &A));
check_access!(t06, true, ());
check_access!(t07, false, (Option<&A>, &mut A));
check_access!(t08, false, (&mut A, Option<&B>, &A, Not<&B>));
check_access!(t09, true, (&mut A, Not<&A>, &A));
check_access!(t10, false, Or<&mut A, &mut A>);
check_access!(t11, true, Xor<&mut A, &mut A>);
check_access!(t12, false, Or<(&A, &B), (&mut B, &C)>);
check_access!(t13, true, (Xor<&mut A, &mut A>, &A));
check_access!(t14, true, (Option<&A>, &A, &A));
check_access!(t15, false, (Xor<(&A, &B), (&B, &C)>, &mut B));
check_access!(t16, true, (Xor<(&A, &B), (&B, &C)>, &B));
check_access!(
t17,
true,
Or<Or<(&mut A, With<&B>), (&A, Not<&B>)>, (&A, Not<&B>)>
);
check_access!(
t18,
true,
(((&mut A, With<&B>), (&A, Not<&B>)), (&A, Not<&B>))
);
check_access!(t19, true, (&mut A, &A, Not<&A>));
check_access!(t20, true, (Not<&A>, &mut A, &A));
macro_rules! check_matching {
(
name = $name:ident,
query = $query:ty,
matches = [$(($($matched_comp:ident),*)),*],
ignores = [$(($($ignored_comp:ident),*)),*],
) => {
#[test]
fn $name() {
let mut world = World::new();
#[allow(unused_mut)]
let mut matching = crate::map::IndexSet::<EntityId>::default();
$(
let e = world.spawn();
matching.insert(e);
$(
world.insert(e, $matched_comp);
)*
)*
$(
#[allow(unused_variables)]
let e = world.spawn();
$(
world.insert(e, $ignored_comp);
)*
)*
#[derive(Component)]
struct Matching(crate::map::IndexSet<EntityId>);
let matching_entity = world.spawn();
world.insert(matching_entity, Matching(matching));
world.add_handler(move |_: Receiver<E>, f: Fetcher<(EntityId, $query)>, matching: Single<&mut Matching>| {
for (e, _) in f {
if e != matching_entity && !matching.0.0.shift_remove(&e) {
panic!("matched entity unexpectedly {e:?}");
}
}
});
world.send(E);
let matching = &world.get::<Matching>(matching_entity).unwrap().0;
if !matching.is_empty() {
panic!("entities not matched: {matching:?}");
}
}
}
}
check_matching! {
name = matching_ref,
query = &A,
matches = [(A), (A, B), (A, B, C)],
ignores = [(), (B), (C), (B, C)],
}
check_matching! {
name = matching_with,
query = With<&A>,
matches = [(A), (A, B), (A, B, C)],
ignores = [(), (B), (C), (B, C)],
}
check_matching! {
name = matching_and,
query = (&A, &mut B),
matches = [(A, B), (A, B, C)],
ignores = [(), (A), (B), (A, C), (B, C)],
}
check_matching! {
name = matching_or,
query = Or<&A, &B>,
matches = [(A), (B), (A, B), (A, B, C), (B, C)],
ignores = [(), (C)],
}
check_matching! {
name = matching_xor,
query = Xor<&A, &mut B>,
matches = [(A), (B), (A, C), (B, C)],
ignores = [(), (A, B), (A, B, C)],
}
check_matching! {
name = matching_option,
query = Option<&A>,
matches = [(), (A), (A, B), (A, B, C)],
ignores = [],
}
check_matching! {
name = matching_entity_id,
query = EntityId,
matches = [(), (A), (A, B), (A, B, C)],
ignores = [],
}
check_matching! {
name = matching_not,
query = Not<&A>,
matches = [(), (B), (B, C)],
ignores = [(A), (A, B), (A, B, C)],
}
check_matching! {
name = matching_and_not,
query = (&mut A, Not<&B>),
matches = [(A), (A, C)],
ignores = [(), (A, B), (B, C), (A, B, C)],
}
check_matching! {
name = matching_phantom_data,
query = PhantomData<()>,
matches = [(), (A), (A, B), (A, B, C)],
ignores = [],
}
#[test]
#[allow(dead_code)]
fn derived_query() {
#[derive(Query)]
struct UnitQuery;
#[derive(Query)]
struct QueryWithLifetime<'a> {
foo: &'a A,
}
#[derive(Query)]
struct QueryWithTwoLifetimes<'a, 'b> {
foo: &'a A,
bar: &'b B,
}
#[derive(Query)]
struct QueryWithTypeParam<'a, T> {
foo: &'a A,
bar: T,
}
#[derive(Query)]
struct TupleStructQuery<'a>(&'a A, &'a mut B);
assert_read_only_query::<UnitQuery>();
assert_read_only_query::<QueryWithLifetime>();
assert_read_only_query::<QueryWithTwoLifetimes>();
assert_read_only_query::<QueryWithTypeParam<()>>();
fn assert_read_only_query<Q: ReadOnlyQuery>() {}
}
}