bevy_trait_query/one/impls/
one_added.rs1use bevy_ecs::ptr::UnsafeCellDeref;
2use std::marker::PhantomData;
3
4use bevy_ecs::{
5 archetype::Archetype,
6 component::{ComponentId, Components, Tick},
7 prelude::{Entity, World},
8 query::{FilteredAccess, QueryData, QueryFilter, ReadOnlyQueryData, WorldQuery},
9 storage::{Table, TableRow},
10 world::unsafe_world_cell::UnsafeWorldCell,
11};
12
13use crate::{
14 ChangeDetectionFetch, ChangeDetectionStorage, TraitQuery, TraitQueryState, debug_unreachable,
15};
16
17pub struct OneAdded<Trait: ?Sized + TraitQuery> {
20 marker: PhantomData<&'static Trait>,
21}
22
23unsafe impl<Trait: ?Sized + TraitQuery> QueryData for OneAdded<Trait> {
24 type ReadOnly = Self;
25
26 const IS_READ_ONLY: bool = true;
27
28 type Item<'w, 's> = bool;
29
30 fn shrink<'wlong: 'wshort, 'wshort, 's>(
31 item: Self::Item<'wlong, 's>,
32 ) -> Self::Item<'wshort, 's> {
33 item
34 }
35
36 #[inline(always)]
37 unsafe fn fetch<'w, 's>(
38 _state: &'s Self::State,
39 fetch: &mut Self::Fetch<'w>,
40 entity: Entity,
41 table_row: TableRow,
42 ) -> Self::Item<'w, 's> {
43 unsafe {
44 let ticks_ptr = match fetch.storage {
45 ChangeDetectionStorage::Uninit => {
46 debug_unreachable()
48 }
49 ChangeDetectionStorage::Table { ticks } => ticks.get(table_row.index()),
50 ChangeDetectionStorage::SparseSet { components } => components
51 .get_added_tick(entity)
52 .unwrap_or_else(|| debug_unreachable()),
53 };
54
55 (*ticks_ptr)
56 .deref()
57 .is_newer_than(fetch.last_run, fetch.this_run)
58 }
59 }
60}
61
62unsafe impl<Trait: ?Sized + TraitQuery> WorldQuery for OneAdded<Trait> {
63 type Fetch<'w> = ChangeDetectionFetch<'w>;
64 type State = TraitQueryState<Trait>;
65
66 unsafe fn init_fetch<'w>(
67 world: UnsafeWorldCell<'w>,
68 _state: &Self::State,
69 last_run: Tick,
70 this_run: Tick,
71 ) -> Self::Fetch<'w> {
72 unsafe {
73 Self::Fetch::<'w> {
74 storage: ChangeDetectionStorage::Uninit,
75 sparse_sets: &world.storages().sparse_sets,
76 last_run,
77 this_run,
78 }
79 }
80 }
81
82 const IS_DENSE: bool = false;
85
86 #[inline]
87 unsafe fn set_archetype<'w>(
88 fetch: &mut Self::Fetch<'w>,
89 state: &Self::State,
90 _archetype: &'w Archetype,
91 table: &'w Table,
92 ) {
93 unsafe {
94 for &component in &*state.components {
97 if let Some(added) = table.get_added_ticks_slice_for(component) {
98 fetch.storage = ChangeDetectionStorage::Table {
99 ticks: added.into(),
100 };
101 return;
102 }
103 }
104 for &component in &*state.components {
105 if let Some(components) = fetch.sparse_sets.get(component) {
106 fetch.storage = ChangeDetectionStorage::SparseSet { components };
107 return;
108 }
109 }
110 debug_unreachable()
112 }
113 }
114
115 #[inline]
116 unsafe fn set_table<'w>(_fetch: &mut Self::Fetch<'w>, _state: &Self::State, _table: &'w Table) {
117 unsafe {
118 debug_unreachable()
120 }
121 }
122
123 #[inline]
124 fn update_component_access(state: &Self::State, access: &mut FilteredAccess) {
125 let mut new_access = access.clone();
126 let mut not_first = false;
127 for &component in &*state.components {
128 assert!(
129 !access.access().has_component_write(component),
130 "&{} conflicts with a previous access in this query. Shared access cannot coincide with exclusive access.",
131 std::any::type_name::<Trait>(),
132 );
133 if not_first {
134 let mut intermediate = access.clone();
135 intermediate.add_component_read(component);
136 new_access.append_or(&intermediate);
137 new_access.extend_access(&intermediate);
138 } else {
139 new_access.and_with(component);
140 new_access.access_mut().add_component_read(component);
141 not_first = true;
142 }
143 }
144 *access = new_access;
145 }
146
147 #[inline]
148 fn init_state(world: &mut World) -> Self::State {
149 TraitQueryState::init(world)
150 }
151
152 #[inline]
153 fn get_state(_: &Components) -> Option<Self::State> {
154 panic!(
156 "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"
157 );
158 }
159
160 fn matches_component_set(
161 state: &Self::State,
162 set_contains_id: &impl Fn(ComponentId) -> bool,
163 ) -> bool {
164 state.matches_component_set_one(set_contains_id)
165 }
166
167 #[inline]
168 fn shrink_fetch<'wlong: 'wshort, 'wshort>(fetch: Self::Fetch<'wlong>) -> Self::Fetch<'wshort> {
169 fetch
170 }
171}
172
173unsafe impl<Trait: ?Sized + TraitQuery> ReadOnlyQueryData for OneAdded<Trait> {}
175unsafe impl<Trait: ?Sized + TraitQuery> QueryFilter for OneAdded<Trait> {
176 const IS_ARCHETYPAL: bool = false;
177 unsafe fn filter_fetch(
178 state: &Self::State,
179 fetch: &mut Self::Fetch<'_>,
180 entity: Entity,
181 table_row: TableRow,
182 ) -> bool {
183 unsafe { <Self as QueryData>::fetch(state, fetch, entity, table_row) }
184 }
185}