bevy_trait_query/all/impls/
all.rs

1use bevy_ecs::{
2    component::{ComponentId, Components, Tick},
3    entity::Entity,
4    query::{QueryData, QueryItem, ReadOnlyQueryData, WorldQuery},
5    storage::TableRow,
6    world::{World, unsafe_world_cell::UnsafeWorldCell},
7};
8
9use crate::{
10    AllTraitsFetch, ReadTraits, TraitQuery, TraitQueryState, WriteTraits, debug_unreachable,
11    trait_registry_error,
12};
13
14/// [`WorldQuery`] adapter that fetches all implementations of a given trait for an entity.
15///
16/// You can usually just use `&dyn Trait` or `&mut dyn Trait` as a [`WorldQuery`] directly. To be
17/// specific, the following queries are equivalent:
18///
19/// - `Query<All<&dyn Trait>>` has the same outcome as `Query<&dyn Trait>`
20/// - `Query<All<&mut dyn Trait>>` has the same outcome as `Query<&mut dyn Trait>`
21///
22/// Depending on whether you requested shared or exclusive access to the trait objects, iterating
23/// over these queries yields types with different capacities
24///
25/// - `Query<&dyn Trait>` yields a [`ReadTraits`] object
26/// - `Query<&mut dyn Trait>` yields a [`WriteTraits`] object
27pub struct All<T: ?Sized>(T);
28
29unsafe impl<Trait: ?Sized + TraitQuery> QueryData for All<&Trait> {
30    type ReadOnly = Self;
31
32    const IS_READ_ONLY: bool = true;
33
34    type Item<'w, 's> = ReadTraits<'w, Trait>;
35
36    #[inline]
37    fn shrink<'wlong: 'wshort, 'wshort, 's>(
38        item: QueryItem<'wlong, 's, Self>,
39    ) -> QueryItem<'wshort, 's, Self> {
40        item
41    }
42
43    #[inline]
44    unsafe fn fetch<'w, 's>(
45        _state: &'s Self::State,
46        fetch: &mut Self::Fetch<'w>,
47        _entity: Entity,
48        table_row: TableRow,
49    ) -> Self::Item<'w, 's> {
50        let table = fetch
51            .table
52            .unwrap_or_else(|| unsafe { debug_unreachable() });
53
54        ReadTraits {
55            registry: fetch.registry,
56            table,
57            table_row,
58            sparse_sets: fetch.sparse_sets,
59            last_run: fetch.last_run,
60            this_run: fetch.this_run,
61        }
62    }
63}
64unsafe impl<Trait: ?Sized + TraitQuery> ReadOnlyQueryData for All<&Trait> {}
65
66// SAFETY: We only access the components registered in the trait registry.
67// This is known to match the set of components in the TraitQueryState,
68// which is used to match archetypes and register world access.
69unsafe impl<Trait: ?Sized + TraitQuery> WorldQuery for All<&Trait> {
70    type Fetch<'w> = AllTraitsFetch<'w, Trait>;
71    type State = TraitQueryState<Trait>;
72
73    #[inline]
74    unsafe fn init_fetch<'w>(
75        world: UnsafeWorldCell<'w>,
76        _state: &Self::State,
77        last_run: Tick,
78        this_run: Tick,
79    ) -> Self::Fetch<'w> {
80        unsafe {
81            AllTraitsFetch {
82                registry: world
83                    .get_resource()
84                    .unwrap_or_else(|| trait_registry_error()),
85                table: None,
86                sparse_sets: &world.storages().sparse_sets,
87                last_run,
88                this_run,
89            }
90        }
91    }
92
93    const IS_DENSE: bool = false;
94
95    #[inline]
96    unsafe fn set_archetype<'w>(
97        fetch: &mut Self::Fetch<'w>,
98        _state: &Self::State,
99        _archetype: &'w bevy_ecs::archetype::Archetype,
100        table: &'w bevy_ecs::storage::Table,
101    ) {
102        fetch.table = Some(table);
103    }
104
105    unsafe fn set_table<'w>(
106        fetch: &mut Self::Fetch<'w>,
107        _state: &Self::State,
108        table: &'w bevy_ecs::storage::Table,
109    ) {
110        fetch.table = Some(table);
111    }
112
113    #[inline]
114    fn update_component_access(state: &Self::State, access: &mut bevy_ecs::query::FilteredAccess) {
115        let mut not_first = false;
116        let mut new_access = access.clone();
117        for &component in &*state.components {
118            assert!(
119                !access.access().has_component_write(component),
120                "&{} conflicts with a previous access in this query. Shared access cannot coincide with exclusive access.",
121                std::any::type_name::<Trait>(),
122            );
123            if not_first {
124                let mut intermediate = access.clone();
125                intermediate.add_component_read(component);
126                new_access.append_or(&intermediate);
127                new_access.extend_access(&intermediate);
128            } else {
129                new_access.and_with(component);
130                new_access.access_mut().add_component_read(component);
131                not_first = true;
132            }
133        }
134        *access = new_access;
135    }
136
137    #[inline]
138    fn init_state(world: &mut World) -> Self::State {
139        TraitQueryState::init(world)
140    }
141
142    #[inline]
143    fn get_state(_: &Components) -> Option<Self::State> {
144        // TODO: fix this https://github.com/bevyengine/bevy/issues/13798
145        panic!(
146            "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"
147        );
148    }
149
150    #[inline]
151    fn matches_component_set(
152        state: &Self::State,
153        set_contains_id: &impl Fn(ComponentId) -> bool,
154    ) -> bool {
155        state.matches_component_set_any(set_contains_id)
156    }
157
158    #[inline]
159    fn shrink_fetch<'wlong: 'wshort, 'wshort>(fetch: Self::Fetch<'wlong>) -> Self::Fetch<'wshort> {
160        fetch
161    }
162}
163
164unsafe impl<'a, Trait: ?Sized + TraitQuery> QueryData for All<&'a mut Trait> {
165    type ReadOnly = All<&'a Trait>;
166
167    const IS_READ_ONLY: bool = false;
168
169    type Item<'w, 's> = WriteTraits<'w, Trait>;
170
171    #[inline]
172    fn shrink<'wlong: 'wshort, 'wshort, 's>(
173        item: QueryItem<'wlong, 's, Self>,
174    ) -> QueryItem<'wshort, 's, Self> {
175        item
176    }
177
178    #[inline]
179    unsafe fn fetch<'w, 's>(
180        _state: &'s Self::State,
181        fetch: &mut Self::Fetch<'w>,
182        _entity: Entity,
183        table_row: TableRow,
184    ) -> Self::Item<'w, 's> {
185        let table = fetch
186            .table
187            .unwrap_or_else(|| unsafe { debug_unreachable() });
188
189        WriteTraits {
190            registry: fetch.registry,
191            table,
192            table_row,
193            sparse_sets: fetch.sparse_sets,
194            last_run: fetch.last_run,
195            this_run: fetch.this_run,
196        }
197    }
198}
199
200// SAFETY: We only access the components registered in the trait registry.
201// This is known to match the set of components in the TraitQueryState,
202// which is used to match archetypes and register world access.
203unsafe impl<Trait: ?Sized + TraitQuery> WorldQuery for All<&mut Trait> {
204    type Fetch<'w> = AllTraitsFetch<'w, Trait>;
205    type State = TraitQueryState<Trait>;
206
207    #[inline]
208    unsafe fn init_fetch<'w>(
209        world: UnsafeWorldCell<'w>,
210        _state: &Self::State,
211        last_run: Tick,
212        this_run: Tick,
213    ) -> Self::Fetch<'w> {
214        unsafe {
215            AllTraitsFetch {
216                registry: world
217                    .get_resource()
218                    .unwrap_or_else(|| trait_registry_error()),
219                table: None,
220                sparse_sets: &world.storages().sparse_sets,
221                last_run,
222                this_run,
223            }
224        }
225    }
226
227    const IS_DENSE: bool = false;
228
229    #[inline]
230    unsafe fn set_archetype<'w>(
231        fetch: &mut Self::Fetch<'w>,
232        _state: &Self::State,
233        _archetype: &'w bevy_ecs::archetype::Archetype,
234        table: &'w bevy_ecs::storage::Table,
235    ) {
236        fetch.table = Some(table);
237    }
238
239    #[inline]
240    unsafe fn set_table<'w>(
241        fetch: &mut Self::Fetch<'w>,
242        _state: &Self::State,
243        table: &'w bevy_ecs::storage::Table,
244    ) {
245        fetch.table = Some(table);
246    }
247
248    #[inline]
249    fn update_component_access(state: &Self::State, access: &mut bevy_ecs::query::FilteredAccess) {
250        let mut not_first = false;
251        let mut new_access = access.clone();
252        for &component in &*state.components {
253            assert!(
254                !access.access().has_component_write(component),
255                "&mut {} conflicts with a previous access in this query. Mutable component access must be unique.",
256                std::any::type_name::<Trait>(),
257            );
258            if not_first {
259                let mut intermediate = access.clone();
260                intermediate.add_component_write(component);
261                new_access.append_or(&intermediate);
262                new_access.extend_access(&intermediate);
263            } else {
264                new_access.and_with(component);
265                new_access.access_mut().add_component_write(component);
266                not_first = true;
267            }
268        }
269        *access = new_access;
270    }
271
272    #[inline]
273    fn init_state(world: &mut World) -> Self::State {
274        TraitQueryState::init(world)
275    }
276
277    #[inline]
278    fn get_state(_: &Components) -> Option<Self::State> {
279        // TODO: fix this https://github.com/bevyengine/bevy/issues/13798
280        panic!(
281            "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"
282        );
283    }
284
285    #[inline]
286    fn matches_component_set(
287        state: &Self::State,
288        set_contains_id: &impl Fn(ComponentId) -> bool,
289    ) -> bool {
290        state.matches_component_set_any(set_contains_id)
291    }
292
293    #[inline]
294    fn shrink_fetch<'wlong: 'wshort, 'wshort>(fetch: Self::Fetch<'wlong>) -> Self::Fetch<'wshort> {
295        fetch
296    }
297}