bevy_trait_query/one/impls/
without_any.rs

1use std::marker::PhantomData;
2
3use bevy_ecs::{
4    component::{ComponentId, Components, Tick},
5    prelude::{Entity, World},
6    query::{ArchetypeFilter, QueryFilter, WorldQuery},
7    storage::TableRow,
8    world::unsafe_world_cell::UnsafeWorldCell,
9};
10
11use crate::{TraitQuery, TraitQueryState};
12
13/// [`WorldQuery`] filter for entities without any [one](crate::One) component
14/// implementing a trait.
15pub struct WithoutAny<Trait: ?Sized + TraitQuery>(PhantomData<&'static Trait>);
16
17// this takes inspiration from `With` in bevy's main repo
18unsafe impl<Trait: ?Sized + TraitQuery> WorldQuery for WithoutAny<Trait> {
19    type Fetch<'w> = ();
20    type State = TraitQueryState<Trait>;
21
22    #[inline]
23    unsafe fn init_fetch(
24        _world: UnsafeWorldCell<'_>,
25        _state: &Self::State,
26        _last_run: Tick,
27        _this_run: Tick,
28    ) {
29    }
30
31    const IS_DENSE: bool = false;
32
33    #[inline]
34    unsafe fn set_archetype<'w>(
35        _fetch: &mut (),
36        _state: &Self::State,
37        _archetype: &'w bevy_ecs::archetype::Archetype,
38        _table: &'w bevy_ecs::storage::Table,
39    ) {
40    }
41
42    #[inline]
43    unsafe fn set_table(_fetch: &mut (), _state: &Self::State, _table: &bevy_ecs::storage::Table) {}
44
45    #[inline]
46    fn update_component_access(state: &Self::State, access: &mut bevy_ecs::query::FilteredAccess) {
47        for &component in &*state.components {
48            assert!(
49                !access.access().has_component_write(component),
50                "&{} conflicts with a previous access in this query. Shared access cannot coincide with exclusive access.",
51                std::any::type_name::<Trait>(),
52            );
53            access.and_without(component);
54        }
55    }
56
57    #[inline]
58    fn init_state(world: &mut World) -> Self::State {
59        TraitQueryState::init(world)
60    }
61
62    #[inline]
63    fn get_state(_: &Components) -> Option<Self::State> {
64        // TODO: fix this https://github.com/bevyengine/bevy/issues/13798
65        panic!(
66            "transmuting and any other operations concerning the state of a query are currently broken and shouldn't be used. See https://github.com/JoJoJet/bevy-trait-query/issues/59"
67        );
68    }
69
70    #[inline]
71    fn matches_component_set(
72        state: &Self::State,
73        set_contains_id: &impl Fn(ComponentId) -> bool,
74    ) -> bool {
75        !state.components.iter().any(|&id| set_contains_id(id))
76    }
77
78    #[inline]
79    fn shrink_fetch<'wlong: 'wshort, 'wshort>(_fetch: Self::Fetch<'wlong>) -> Self::Fetch<'wshort> {
80    }
81}
82
83impl<Trait: ?Sized + TraitQuery> ArchetypeFilter for WithoutAny<Trait> {}
84
85/// SAFETY: read-only access
86unsafe impl<Trait: ?Sized + TraitQuery> QueryFilter for WithoutAny<Trait> {
87    const IS_ARCHETYPAL: bool = false;
88    unsafe fn filter_fetch(
89        _state: &Self::State,
90        _fetch: &mut Self::Fetch<'_>,
91        _entity: Entity,
92        _table_row: TableRow,
93    ) -> bool {
94        true
95    }
96}