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
18unsafe 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
34unsafe impl<T: Component, Pred: Predicate<T>> ReadOnlyWorldQuery for Check<T, Pred> {}
36
37pub 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
56pub struct CheckFetch<'w, T, Pred> {
58 pred_marker: PhantomData<Pred>,
59 table_components: Option<ThinSlicePtr<'w, UnsafeCell<T>>>,
61 entity_table_rows: Option<ThinSlicePtr<'w, usize>>,
62 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
79unsafe 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}