1use bevy_ecs::change_detection::{Mut, Ref, Tick};
2use bevy_ecs::entity::Entity;
3use bevy_ecs::prelude::World;
4use bevy_ecs::ptr::UnsafeCellDeref;
5use bevy_ecs::query::{IterQueryData, SingleEntityQueryData};
6use bevy_ecs::{
7 component::{ComponentId, Components},
8 query::{QueryData, QueryItem, ReadOnlyQueryData, WorldQuery},
9 storage::TableRow,
10 world::unsafe_world_cell::UnsafeWorldCell,
11};
12
13use crate::TraitImplMeta;
14use crate::{
15 OneTraitFetch, TraitQuery, TraitQueryState, debug_unreachable, one::FetchStorage, zip_exact,
16};
17
18pub struct One<T>(pub T);
26
27unsafe impl<Trait: ?Sized + TraitQuery> IterQueryData for One<&Trait> {}
28unsafe impl<Trait: ?Sized + TraitQuery> SingleEntityQueryData for One<&Trait> {}
29unsafe impl<Trait: ?Sized + TraitQuery> QueryData for One<&Trait> {
30 type ReadOnly = Self;
31
32 const IS_READ_ONLY: bool = true;
33 const IS_ARCHETYPAL: bool = false;
34
35 type Item<'w, 's> = Ref<'w, Trait>;
36
37 #[inline]
38 fn shrink<'wlong: 'wshort, 'wshort, 's>(
39 item: QueryItem<'wlong, 's, Self>,
40 ) -> QueryItem<'wshort, 's, Self> {
41 item
42 }
43
44 #[inline]
45 unsafe fn fetch<'w, 's>(
46 _state: &'s Self::State,
47 fetch: &mut Self::Fetch<'w>,
48 entity: Entity,
49 table_row: TableRow,
50 ) -> Option<Self::Item<'w, 's>> {
51 unsafe {
52 let table_row = table_row.index();
53 let (dyn_ctor, ptr, added, changed, location) = match fetch.storage {
54 FetchStorage::Uninit => debug_unreachable(),
57 FetchStorage::Table {
58 column,
59 added_ticks,
60 changed_ticks,
61 location,
62 meta,
63 } => {
64 let ptr = column.byte_add(table_row * meta.size_bytes);
65 (
66 meta.dyn_ctor,
67 ptr,
68 added_ticks.get_unchecked(table_row).deref(),
71 changed_ticks.get_unchecked(table_row).deref(),
72 location,
73 )
74 }
75 FetchStorage::SparseSet { components, meta } => {
76 let (ptr, ticks) = components
77 .get_with_ticks(entity)
78 .unwrap_or_else(|| debug_unreachable());
79 (
80 meta.dyn_ctor,
81 ptr,
82 ticks.added.deref(),
85 ticks.changed.deref(),
86 ticks.changed_by,
87 )
88 }
89 };
90
91 Some(Ref::new(
92 dyn_ctor.cast(ptr),
93 added,
94 changed,
95 fetch.last_run,
96 fetch.this_run,
97 location.map(|loc| loc.deref()),
98 ))
99 }
100 }
101
102 fn iter_access(
103 _state: &Self::State,
104 ) -> impl Iterator<Item = bevy_ecs::query::EcsAccessType<'_>> {
105 core::iter::empty()
106 }
107}
108
109unsafe impl<Trait: ?Sized + TraitQuery> ReadOnlyQueryData for One<&Trait> {}
110
111unsafe impl<Trait: ?Sized + TraitQuery> WorldQuery for One<&Trait> {
114 type Fetch<'w> = OneTraitFetch<'w, Trait>;
115 type State = TraitQueryState<Trait>;
116
117 #[inline]
118 unsafe fn init_fetch<'w>(
119 world: UnsafeWorldCell<'w>,
120 _state: &Self::State,
121 _last_run: Tick,
122 _this_run: Tick,
123 ) -> OneTraitFetch<'w, Trait> {
124 unsafe {
125 OneTraitFetch {
126 storage: FetchStorage::Uninit,
127 last_run: Tick::new(0),
128 sparse_sets: &world.storages().sparse_sets,
129 this_run: Tick::new(0),
130 }
131 }
132 }
133
134 const IS_DENSE: bool = false;
135 #[inline]
138 unsafe fn set_archetype<'w>(
139 fetch: &mut OneTraitFetch<'w, Trait>,
140 state: &Self::State,
141 _archetype: &'w bevy_ecs::archetype::Archetype,
142 table: &'w bevy_ecs::storage::Table,
143 ) {
144 unsafe {
145 let row = TableRow::new(0_u16.into());
151 for (&component_id, &meta) in zip_exact(&*state.components, &*state.meta) {
152 if let Some(table_storage) = get_table_fetch_data(table, component_id, row, meta) {
153 fetch.storage = table_storage;
154 return;
155 }
156 }
157 for (&component, &meta) in zip_exact(&*state.components, &*state.meta) {
158 if let Some(sparse_set) = fetch.sparse_sets.get(component) {
159 fetch.storage = FetchStorage::SparseSet {
160 components: sparse_set,
161 meta,
162 };
163 return;
164 }
165 }
166 debug_unreachable()
168 }
169 }
170
171 #[inline]
172 unsafe fn set_table<'w>(
173 fetch: &mut OneTraitFetch<'w, Trait>,
174 state: &Self::State,
175 table: &'w bevy_ecs::storage::Table,
176 ) {
177 unsafe {
178 let row = TableRow::new(0_u16.into());
183 for (&component_id, &meta) in core::iter::zip(&*state.components, &*state.meta) {
184 if let Some(table_storage) = get_table_fetch_data(table, component_id, row, meta) {
185 fetch.storage = table_storage;
186 return;
187 }
188 }
189 debug_unreachable()
191 }
192 }
193
194 #[inline]
195 fn update_component_access(state: &Self::State, access: &mut bevy_ecs::query::FilteredAccess) {
196 let mut new_access = access.clone();
197 let mut not_first = false;
198 for &component in &*state.components {
199 assert!(
200 !access.access().has_write(component),
201 "&{} conflicts with a previous access in this query. Shared access cannot coincide with exclusive access.",
202 core::any::type_name::<Trait>(),
203 );
204 if not_first {
205 let mut intermediate = access.clone();
206 intermediate.add_read(component);
207 new_access.append_or(&intermediate);
208 new_access.extend_access(&intermediate);
209 } else {
210 new_access.and_with(component);
211 new_access.access_mut().add_read(component);
212 not_first = true;
213 }
214 }
215 *access = new_access;
216 }
217
218 #[inline]
219 fn init_state(world: &mut World) -> Self::State {
220 TraitQueryState::init(world)
221 }
222
223 #[inline]
224 fn get_state(_: &Components) -> Option<Self::State> {
225 panic!(
227 "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"
228 );
229 }
230
231 #[inline]
232 fn matches_component_set(
233 state: &Self::State,
234 set_contains_id: &impl Fn(ComponentId) -> bool,
235 ) -> bool {
236 state.matches_component_set_one(set_contains_id)
237 }
238
239 #[inline]
240 fn shrink_fetch<'wlong: 'wshort, 'wshort>(fetch: Self::Fetch<'wlong>) -> Self::Fetch<'wshort> {
241 fetch
242 }
243}
244
245unsafe impl<Trait: ?Sized + TraitQuery> IterQueryData for One<&mut Trait> {}
246unsafe impl<Trait: ?Sized + TraitQuery> SingleEntityQueryData for One<&mut Trait> {}
247unsafe impl<'a, Trait: ?Sized + TraitQuery> QueryData for One<&'a mut Trait> {
248 type ReadOnly = One<&'a Trait>;
249
250 const IS_READ_ONLY: bool = false;
251 const IS_ARCHETYPAL: bool = false;
252
253 type Item<'w, 's> = Mut<'w, Trait>;
254
255 #[inline]
256 fn shrink<'wlong: 'wshort, 'wshort, 's>(
257 item: QueryItem<'wlong, 's, Self>,
258 ) -> QueryItem<'wshort, 's, Self> {
259 item
260 }
261
262 #[inline]
263 unsafe fn fetch<'w>(
264 _state: &Self::State,
265 fetch: &mut Self::Fetch<'w>,
266 entity: Entity,
267 table_row: TableRow,
268 ) -> Option<Mut<'w, Trait>> {
269 unsafe {
270 let table_row = table_row.index();
271 let (dyn_ctor, ptr, added, changed, location) = match fetch.storage {
272 FetchStorage::Uninit => debug_unreachable(),
275 FetchStorage::Table {
276 column,
277 added_ticks,
278 changed_ticks,
279 location,
280 meta,
281 } => {
282 let ptr = column.byte_add(table_row * meta.size_bytes);
283 (
284 meta.dyn_ctor,
285 ptr.assert_unique(),
289 added_ticks.get_unchecked(table_row).deref_mut(),
292 changed_ticks.get_unchecked(table_row).deref_mut(),
293 location,
294 )
295 }
296 FetchStorage::SparseSet { components, meta } => {
297 let (ptr, ticks) = components
298 .get_with_ticks(entity)
299 .unwrap_or_else(|| debug_unreachable());
300 (
301 meta.dyn_ctor,
302 ptr.assert_unique(),
306 ticks.added.deref_mut(),
309 ticks.changed.deref_mut(),
310 ticks.changed_by,
311 )
312 }
313 };
314
315 Some(Mut::new(
316 dyn_ctor.cast_mut(ptr),
317 added,
318 changed,
319 fetch.last_run,
320 fetch.this_run,
321 location.map(|loc| loc.deref_mut()),
322 ))
323 }
324 }
325
326 fn iter_access(
327 _state: &Self::State,
328 ) -> impl Iterator<Item = bevy_ecs::query::EcsAccessType<'_>> {
329 core::iter::empty()
330 }
331}
332
333unsafe impl<Trait: ?Sized + TraitQuery> WorldQuery for One<&mut Trait> {
336 type Fetch<'w> = OneTraitFetch<'w, Trait>;
337 type State = TraitQueryState<Trait>;
338
339 #[inline]
340 unsafe fn init_fetch<'w>(
341 world: UnsafeWorldCell<'w>,
342 _state: &Self::State,
343 last_run: Tick,
344 this_run: Tick,
345 ) -> OneTraitFetch<'w, Trait> {
346 unsafe {
347 OneTraitFetch {
348 storage: FetchStorage::Uninit,
349 sparse_sets: &world.storages().sparse_sets,
350 last_run,
351 this_run,
352 }
353 }
354 }
355
356 const IS_DENSE: bool = false;
357
358 #[inline]
359 unsafe fn set_archetype<'w>(
360 fetch: &mut OneTraitFetch<'w, Trait>,
361 state: &Self::State,
362 _archetype: &'w bevy_ecs::archetype::Archetype,
363 table: &'w bevy_ecs::storage::Table,
364 ) {
365 unsafe {
366 let row = TableRow::new(0_u16.into());
371 for (&component_id, &meta) in zip_exact(&*state.components, &*state.meta) {
372 if let Some(table_storage) = get_table_fetch_data(table, component_id, row, meta) {
373 fetch.storage = table_storage;
374 return;
375 }
376 }
377 for (&component, &meta) in zip_exact(&*state.components, &*state.meta) {
378 if let Some(sparse_set) = fetch.sparse_sets.get(component) {
379 fetch.storage = FetchStorage::SparseSet {
380 components: sparse_set,
381 meta,
382 };
383 return;
384 }
385 }
386 debug_unreachable()
388 }
389 }
390
391 #[inline]
392 unsafe fn set_table<'w>(
393 fetch: &mut OneTraitFetch<'w, Trait>,
394 state: &Self::State,
395 table: &'w bevy_ecs::storage::Table,
396 ) {
397 unsafe {
398 let row = TableRow::new(0_u16.into());
403 for (&component_id, &meta) in core::iter::zip(&*state.components, &*state.meta) {
404 if let Some(table_storage) = get_table_fetch_data(table, component_id, row, meta) {
405 fetch.storage = table_storage;
406 return;
407 }
408 }
409 debug_unreachable()
411 }
412 }
413
414 #[inline]
415 fn update_component_access(state: &Self::State, access: &mut bevy_ecs::query::FilteredAccess) {
416 let mut new_access = access.clone();
417 let mut not_first = false;
418 for &component in &*state.components {
419 assert!(
420 !access.access().has_write(component),
421 "&mut {} conflicts with a previous access in this query. Mutable component access must be unique.",
422 core::any::type_name::<Trait>(),
423 );
424 if not_first {
425 let mut intermediate = access.clone();
426 intermediate.add_write(component);
427 new_access.append_or(&intermediate);
428 new_access.extend_access(&intermediate);
429 } else {
430 new_access.and_with(component);
431 new_access.access_mut().add_write(component);
432 not_first = true;
433 }
434 }
435 *access = new_access;
436 }
437
438 #[inline]
439 fn init_state(world: &mut World) -> Self::State {
440 TraitQueryState::init(world)
441 }
442
443 #[inline]
444 fn get_state(_: &Components) -> Option<Self::State> {
445 panic!(
447 "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"
448 );
449 }
450
451 #[inline]
452 fn matches_component_set(
453 state: &Self::State,
454 set_contains_id: &impl Fn(ComponentId) -> bool,
455 ) -> bool {
456 state.matches_component_set_one(set_contains_id)
457 }
458
459 #[inline]
460 fn shrink_fetch<'wlong: 'wshort, 'wshort>(fetch: Self::Fetch<'wlong>) -> Self::Fetch<'wshort> {
461 fetch
462 }
463}
464
465#[inline]
467unsafe fn get_table_fetch_data<Trait: ?Sized + TraitQuery>(
468 table: &'_ bevy_ecs::storage::Table,
469 component_id: ComponentId,
470 row: TableRow,
471 meta: TraitImplMeta<Trait>,
472) -> Option<FetchStorage<'_, Trait>> {
473 unsafe {
474 let ptr = table.get_component(component_id, row)?;
475 let location = table.get_changed_by(component_id, row).transpose()?;
476 let added = table.get_added_ticks_slice_for(component_id)?;
477 let changed = table.get_changed_ticks_slice_for(component_id)?;
478 Some(FetchStorage::Table {
479 column: ptr,
480 added_ticks: added.into(),
481 changed_ticks: changed.into(),
482 location,
483 meta,
484 })
485 }
486}