bevy_mod_check_filter/
impls.rs

1use std::{cell::UnsafeCell, marker::PhantomData};
2
3use bevy_ecs::{
4    archetype::{Archetype, ArchetypeComponentId},
5    component::{Component, ComponentId, ComponentStorage, StorageType},
6    entity::Entity,
7    query::{
8        Access, Fetch, FetchState, FilteredAccess, QueryItem, ReadOnlyWorldQuery, WorldQuery,
9        WorldQueryGats,
10    },
11    storage::{ComponentSparseSet, Table, Tables},
12    world::World,
13};
14use bevy_ptr::{ThinSlicePtr, UnsafeCellDeref};
15
16use crate::{Check, Predicate};
17
18// SAFETY: `ROQueryFetch<Self>` is the same as `QueryFetch<Self>`
19unsafe impl<T: Component, Pred: Predicate<T>> WorldQuery for Check<T, Pred> {
20    type ReadOnly = Self;
21
22    type State = CheckState<T>;
23
24    fn shrink<'wlong: 'wshort, 'wshort>(item: QueryItem<'wlong, Self>) -> QueryItem<'wshort, Self> {
25        item
26    }
27}
28
29impl<'w, T: Component, Pred: Predicate<T>> WorldQueryGats<'w> for Check<T, Pred> {
30    type Fetch = CheckFetch<'w, T, Pred>;
31    type _State = CheckState<T>;
32}
33
34// SAFETY: read-only access
35unsafe impl<T: Component, Pred: Predicate<T>> ReadOnlyWorldQuery for Check<T, Pred> {}
36
37/// The [`FetchState`] of [`Equals`].
38pub struct CheckState<T> {
39    component_id: ComponentId,
40    marker: PhantomData<T>,
41}
42
43impl<T: Component> FetchState for CheckState<T> {
44    fn init(world: &mut World) -> Self {
45        Self {
46            component_id: world.init_component::<T>(),
47            marker: PhantomData,
48        }
49    }
50
51    fn matches_component_set(&self, set_contains_id: &impl Fn(ComponentId) -> bool) -> bool {
52        set_contains_id(self.component_id)
53    }
54}
55
56/// The [`Fetch`] of [`Equals`].
57pub struct CheckFetch<'w, T, Pred> {
58    pred_marker: PhantomData<Pred>,
59    // T::Storage = TableStorage
60    table_components: Option<ThinSlicePtr<'w, UnsafeCell<T>>>,
61    entity_table_rows: Option<ThinSlicePtr<'w, usize>>,
62    // T::Storage = SparseStorage
63    entities: Option<ThinSlicePtr<'w, Entity>>,
64    sparse_set: Option<&'w ComponentSparseSet>,
65}
66
67impl<T, Pred> Clone for CheckFetch<'_, T, Pred> {
68    fn clone(&self) -> Self {
69        Self {
70            pred_marker: PhantomData,
71            table_components: self.table_components,
72            entity_table_rows: self.entity_table_rows,
73            entities: self.entities,
74            sparse_set: self.sparse_set,
75        }
76    }
77}
78
79// SAFETY: this reads the T component. archetype component access and component access are updated to reflect that
80unsafe impl<'w, T: Component, Pred: Predicate<T>> Fetch<'w> for CheckFetch<'w, T, Pred> {
81    type Item = bool;
82    type State = CheckState<T>;
83
84    unsafe fn init(
85        world: &'w World,
86        state: &Self::State,
87        _last_change_tick: u32,
88        _change_tick: u32,
89    ) -> Self {
90        Self {
91            pred_marker: PhantomData,
92            table_components: None,
93            entity_table_rows: None,
94            entities: None,
95            sparse_set: (T::Storage::STORAGE_TYPE == StorageType::SparseSet).then(|| {
96                world
97                    .storages()
98                    .sparse_sets
99                    .get(state.component_id)
100                    .unwrap()
101            }),
102        }
103    }
104
105    const IS_DENSE: bool = {
106        match T::Storage::STORAGE_TYPE {
107            StorageType::Table => true,
108            StorageType::SparseSet => false,
109        }
110    };
111
112    const IS_ARCHETYPAL: bool = true;
113
114    unsafe fn set_archetype(
115        &mut self,
116        state: &Self::State,
117        archetype: &'w Archetype,
118        tables: &'w Tables,
119    ) {
120        match T::Storage::STORAGE_TYPE {
121            StorageType::Table => {
122                self.entity_table_rows = Some(archetype.entity_table_rows().into());
123                let column = tables[archetype.table_id()]
124                    .get_column(state.component_id)
125                    .unwrap();
126                self.table_components = Some(column.get_data_slice().into());
127            }
128            StorageType::SparseSet => self.entities = Some(archetype.entities().into()),
129        }
130    }
131
132    unsafe fn set_table(&mut self, state: &Self::State, table: &'w Table) {
133        self.table_components = Some(
134            table
135                .get_column(state.component_id)
136                .unwrap()
137                .get_data_slice()
138                .into(),
139        );
140    }
141
142    unsafe fn archetype_fetch(&mut self, archetype_index: usize) -> Self::Item {
143        let item = match T::Storage::STORAGE_TYPE {
144            StorageType::Table => {
145                let (entity_table_rows, table_components) = self
146                    .entity_table_rows
147                    .zip(self.table_components)
148                    .unwrap_or_else(|| debug_checked_unreachable());
149                let table_row = *entity_table_rows.get(archetype_index);
150                table_components.get(table_row).deref()
151            }
152            StorageType::SparseSet => {
153                let (entities, sparse_set) = self
154                    .entities
155                    .zip(self.sparse_set)
156                    .unwrap_or_else(|| debug_checked_unreachable());
157                let entity = *entities.get(archetype_index);
158                sparse_set
159                    .get(entity)
160                    .unwrap_or_else(|| debug_checked_unreachable())
161                    .deref::<T>()
162            }
163        };
164        Pred::test(item)
165    }
166
167    unsafe fn table_fetch(&mut self, table_row: usize) -> Self::Item {
168        let components = self
169            .table_components
170            .unwrap_or_else(|| debug_checked_unreachable());
171        let item = components.get(table_row).deref();
172        Pred::test(item)
173    }
174
175    unsafe fn archetype_filter_fetch(&mut self, archetype_index: usize) -> bool {
176        self.archetype_fetch(archetype_index)
177    }
178
179    unsafe fn table_filter_fetch(&mut self, table_row: usize) -> bool {
180        self.table_fetch(table_row)
181    }
182
183    fn update_component_access(state: &Self::State, access: &mut FilteredAccess<ComponentId>) {
184        assert!(
185            !access.access().has_write(state.component_id),
186            "Equals<{}, _> conflicts with a previous access in this query. Shared access cannot coincide with exclusive access.",
187                std::any::type_name::<T>(),
188        );
189        access.add_read(state.component_id);
190    }
191
192    fn update_archetype_component_access(
193        state: &Self::State,
194        archetype: &Archetype,
195        access: &mut Access<ArchetypeComponentId>,
196    ) {
197        if let Some(archetype_component_id) =
198            archetype.get_archetype_component_id(state.component_id)
199        {
200            access.add_read(archetype_component_id);
201        }
202    }
203}
204
205unsafe fn debug_checked_unreachable() -> ! {
206    #[cfg(debug_assertions)]
207    unreachable!();
208    #[cfg(not(debug_assertions))]
209    std::hint::unreachable_unchecked();
210}