constrain WorldQuery::get_state to only use &Components (#13343)
# Objective Passing `&World` in the `WorldQuery::get_state` method is unnecessary, as all implementations of this method in the engine either only access `Components` in `&World`, or do nothing with it. It can introduce UB by necessitating the creation of a `&World` from a `UnsafeWorldCell`. This currently happens in `Query::transmute_lens`, which obtains a `&World` from the internal `UnsafeWorldCell` solely to pass to `get_state`. `Query::join` suffers from the same issue. Other cases of UB come from allowing implementors of `WorldQuery` to freely access `&World`, like in the `bevy-trait-query` crate, where a [reference to a resource is obtained](0c0e7dd646/src/lib.rs (L445)) inside of [`get_state`](0c0e7dd646/src/one.rs (L245)), potentially aliasing with a `ResMut` parameter in the same system. `WorldQuery::init_state` currently requires `&mut World`, which doesn't suffer from these issues. But that too can be changed to receive a wrapper around `&mut Components` and `&mut Storages` for consistency in a follow-up PR. ## Solution Replace the `&World` parameter in `get_state` with `&Components`. ## Changelog `WorldQuery::get_state` now takes `&Components` instead of `&World`. The `transmute`, `transmute_filtered`, `join` and `join_filtered` methods on `QueryState` now similarly take `&Components` instead of `&World`. ## Migration Guide Users of `WorldQuery::get_state` or `transmute`, `transmute_filtered`, `join` and `join_filtered` methods on `QueryState` now need to pass `&Components` instead of `&World`. `&Components` can be trivially obtained from either `components` method on `&World` or `UnsafeWorldCell`. For implementors of `WorldQuery::get_state` that were accessing more than the `Components` inside `&World` and its methods, this is no longer allowed.
This commit is contained in:
		
							parent
							
								
									2037b880ac
								
							
						
					
					
						commit
						0eb4bb6bab
					
				@ -170,9 +170,9 @@ pub(crate) fn world_query_impl(
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            fn get_state(world: &#path::world::World) -> Option<#state_struct_name #user_ty_generics> {
 | 
			
		||||
            fn get_state(components: &#path::component::Components) -> Option<#state_struct_name #user_ty_generics> {
 | 
			
		||||
                Some(#state_struct_name {
 | 
			
		||||
                    #(#named_field_idents: <#field_types>::get_state(world)?,)*
 | 
			
		||||
                    #(#named_field_idents: <#field_types>::get_state(components)?,)*
 | 
			
		||||
                })
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -1,7 +1,7 @@
 | 
			
		||||
use crate::{
 | 
			
		||||
    archetype::{Archetype, Archetypes},
 | 
			
		||||
    change_detection::{Ticks, TicksMut},
 | 
			
		||||
    component::{Component, ComponentId, StorageType, Tick},
 | 
			
		||||
    component::{Component, ComponentId, Components, StorageType, Tick},
 | 
			
		||||
    entity::{Entities, Entity, EntityLocation},
 | 
			
		||||
    query::{Access, DebugCheckedUnwrap, FilteredAccess, WorldQuery},
 | 
			
		||||
    storage::{ComponentSparseSet, Table, TableRow},
 | 
			
		||||
@ -333,7 +333,7 @@ unsafe impl WorldQuery for Entity {
 | 
			
		||||
 | 
			
		||||
    fn init_state(_world: &mut World) {}
 | 
			
		||||
 | 
			
		||||
    fn get_state(_world: &World) -> Option<()> {
 | 
			
		||||
    fn get_state(_components: &Components) -> Option<()> {
 | 
			
		||||
        Some(())
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
@ -405,7 +405,7 @@ unsafe impl WorldQuery for EntityLocation {
 | 
			
		||||
 | 
			
		||||
    fn init_state(_world: &mut World) {}
 | 
			
		||||
 | 
			
		||||
    fn get_state(_world: &World) -> Option<()> {
 | 
			
		||||
    fn get_state(_components: &Components) -> Option<()> {
 | 
			
		||||
        Some(())
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
@ -484,7 +484,7 @@ unsafe impl<'a> WorldQuery for EntityRef<'a> {
 | 
			
		||||
 | 
			
		||||
    fn init_state(_world: &mut World) {}
 | 
			
		||||
 | 
			
		||||
    fn get_state(_world: &World) -> Option<()> {
 | 
			
		||||
    fn get_state(_components: &Components) -> Option<()> {
 | 
			
		||||
        Some(())
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
@ -560,7 +560,7 @@ unsafe impl<'a> WorldQuery for EntityMut<'a> {
 | 
			
		||||
 | 
			
		||||
    fn init_state(_world: &mut World) {}
 | 
			
		||||
 | 
			
		||||
    fn get_state(_world: &World) -> Option<()> {
 | 
			
		||||
    fn get_state(_components: &Components) -> Option<()> {
 | 
			
		||||
        Some(())
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
@ -660,7 +660,7 @@ unsafe impl<'a> WorldQuery for FilteredEntityRef<'a> {
 | 
			
		||||
        FilteredAccess::default()
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    fn get_state(_world: &World) -> Option<Self::State> {
 | 
			
		||||
    fn get_state(_components: &Components) -> Option<Self::State> {
 | 
			
		||||
        Some(FilteredAccess::default())
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
@ -772,7 +772,7 @@ unsafe impl<'a> WorldQuery for FilteredEntityMut<'a> {
 | 
			
		||||
        FilteredAccess::default()
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    fn get_state(_world: &World) -> Option<Self::State> {
 | 
			
		||||
    fn get_state(_components: &Components) -> Option<Self::State> {
 | 
			
		||||
        Some(FilteredAccess::default())
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
@ -844,7 +844,7 @@ unsafe impl WorldQuery for &Archetype {
 | 
			
		||||
 | 
			
		||||
    fn init_state(_world: &mut World) {}
 | 
			
		||||
 | 
			
		||||
    fn get_state(_world: &World) -> Option<()> {
 | 
			
		||||
    fn get_state(_components: &Components) -> Option<()> {
 | 
			
		||||
        Some(())
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
@ -995,8 +995,8 @@ unsafe impl<T: Component> WorldQuery for &T {
 | 
			
		||||
        world.init_component::<T>()
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    fn get_state(world: &World) -> Option<Self::State> {
 | 
			
		||||
        world.component_id::<T>()
 | 
			
		||||
    fn get_state(components: &Components) -> Option<Self::State> {
 | 
			
		||||
        components.component_id::<T>()
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    fn matches_component_set(
 | 
			
		||||
@ -1178,8 +1178,8 @@ unsafe impl<'__w, T: Component> WorldQuery for Ref<'__w, T> {
 | 
			
		||||
        world.init_component::<T>()
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    fn get_state(world: &World) -> Option<Self::State> {
 | 
			
		||||
        world.component_id::<T>()
 | 
			
		||||
    fn get_state(components: &Components) -> Option<Self::State> {
 | 
			
		||||
        components.component_id::<T>()
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    fn matches_component_set(
 | 
			
		||||
@ -1361,8 +1361,8 @@ unsafe impl<'__w, T: Component> WorldQuery for &'__w mut T {
 | 
			
		||||
        world.init_component::<T>()
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    fn get_state(world: &World) -> Option<Self::State> {
 | 
			
		||||
        world.component_id::<T>()
 | 
			
		||||
    fn get_state(components: &Components) -> Option<Self::State> {
 | 
			
		||||
        components.component_id::<T>()
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    fn matches_component_set(
 | 
			
		||||
@ -1480,8 +1480,8 @@ unsafe impl<T: WorldQuery> WorldQuery for Option<T> {
 | 
			
		||||
        T::init_state(world)
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    fn get_state(world: &World) -> Option<Self::State> {
 | 
			
		||||
        T::get_state(world)
 | 
			
		||||
    fn get_state(components: &Components) -> Option<Self::State> {
 | 
			
		||||
        T::get_state(components)
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    fn matches_component_set(
 | 
			
		||||
@ -1635,8 +1635,8 @@ unsafe impl<T: Component> WorldQuery for Has<T> {
 | 
			
		||||
        world.init_component::<T>()
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    fn get_state(world: &World) -> Option<Self::State> {
 | 
			
		||||
        world.component_id::<T>()
 | 
			
		||||
    fn get_state(components: &Components) -> Option<Self::State> {
 | 
			
		||||
        components.component_id::<T>()
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    fn matches_component_set(
 | 
			
		||||
@ -1776,13 +1776,13 @@ macro_rules! impl_anytuple_fetch {
 | 
			
		||||
 | 
			
		||||
                *_access = _new_access;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            fn init_state(_world: &mut World) -> Self::State {
 | 
			
		||||
                ($($name::init_state(_world),)*)
 | 
			
		||||
            #[allow(unused_variables)]
 | 
			
		||||
            fn init_state(world: &mut World) -> Self::State {
 | 
			
		||||
                ($($name::init_state(world),)*)
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            fn get_state(_world: &World) -> Option<Self::State> {
 | 
			
		||||
                Some(($($name::get_state(_world)?,)*))
 | 
			
		||||
            #[allow(unused_variables)]
 | 
			
		||||
            fn get_state(components: &Components) -> Option<Self::State> {
 | 
			
		||||
                Some(($($name::get_state(components)?,)*))
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            fn matches_component_set(_state: &Self::State, _set_contains_id: &impl Fn(ComponentId) -> bool) -> bool {
 | 
			
		||||
@ -1858,8 +1858,8 @@ unsafe impl<D: QueryData> WorldQuery for NopWorldQuery<D> {
 | 
			
		||||
        D::init_state(world)
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    fn get_state(world: &World) -> Option<Self::State> {
 | 
			
		||||
        D::get_state(world)
 | 
			
		||||
    fn get_state(components: &Components) -> Option<Self::State> {
 | 
			
		||||
        D::get_state(components)
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    fn matches_component_set(
 | 
			
		||||
@ -1923,7 +1923,7 @@ unsafe impl<T: ?Sized> WorldQuery for PhantomData<T> {
 | 
			
		||||
 | 
			
		||||
    fn init_state(_world: &mut World) -> Self::State {}
 | 
			
		||||
 | 
			
		||||
    fn get_state(_world: &World) -> Option<Self::State> {
 | 
			
		||||
    fn get_state(_components: &Components) -> Option<Self::State> {
 | 
			
		||||
        Some(())
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -1,6 +1,6 @@
 | 
			
		||||
use crate::{
 | 
			
		||||
    archetype::Archetype,
 | 
			
		||||
    component::{Component, ComponentId, StorageType, Tick},
 | 
			
		||||
    component::{Component, ComponentId, Components, StorageType, Tick},
 | 
			
		||||
    entity::Entity,
 | 
			
		||||
    query::{DebugCheckedUnwrap, FilteredAccess, WorldQuery},
 | 
			
		||||
    storage::{Column, ComponentSparseSet, Table, TableRow},
 | 
			
		||||
@ -183,8 +183,8 @@ unsafe impl<T: Component> WorldQuery for With<T> {
 | 
			
		||||
        world.init_component::<T>()
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    fn get_state(world: &World) -> Option<Self::State> {
 | 
			
		||||
        world.component_id::<T>()
 | 
			
		||||
    fn get_state(components: &Components) -> Option<Self::State> {
 | 
			
		||||
        components.component_id::<T>()
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    fn matches_component_set(
 | 
			
		||||
@ -291,8 +291,8 @@ unsafe impl<T: Component> WorldQuery for Without<T> {
 | 
			
		||||
        world.init_component::<T>()
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    fn get_state(world: &World) -> Option<Self::State> {
 | 
			
		||||
        world.component_id::<T>()
 | 
			
		||||
    fn get_state(components: &Components) -> Option<Self::State> {
 | 
			
		||||
        components.component_id::<T>()
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    fn matches_component_set(
 | 
			
		||||
@ -461,8 +461,8 @@ macro_rules! impl_or_query_filter {
 | 
			
		||||
                ($($filter::init_state(world),)*)
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            fn get_state(world: &World) -> Option<Self::State> {
 | 
			
		||||
                Some(($($filter::get_state(world)?,)*))
 | 
			
		||||
            fn get_state(components: &Components) -> Option<Self::State> {
 | 
			
		||||
                Some(($($filter::get_state(components)?,)*))
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            fn matches_component_set(_state: &Self::State, _set_contains_id: &impl Fn(ComponentId) -> bool) -> bool {
 | 
			
		||||
@ -691,8 +691,8 @@ unsafe impl<T: Component> WorldQuery for Added<T> {
 | 
			
		||||
        world.init_component::<T>()
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    fn get_state(world: &World) -> Option<ComponentId> {
 | 
			
		||||
        world.component_id::<T>()
 | 
			
		||||
    fn get_state(components: &Components) -> Option<ComponentId> {
 | 
			
		||||
        components.component_id::<T>()
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    fn matches_component_set(
 | 
			
		||||
@ -900,8 +900,8 @@ unsafe impl<T: Component> WorldQuery for Changed<T> {
 | 
			
		||||
        world.init_component::<T>()
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    fn get_state(world: &World) -> Option<ComponentId> {
 | 
			
		||||
        world.component_id::<T>()
 | 
			
		||||
    fn get_state(components: &Components) -> Option<ComponentId> {
 | 
			
		||||
        components.component_id::<T>()
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    fn matches_component_set(
 | 
			
		||||
 | 
			
		||||
@ -1,7 +1,7 @@
 | 
			
		||||
use crate::{
 | 
			
		||||
    archetype::{Archetype, ArchetypeComponentId, ArchetypeGeneration, ArchetypeId},
 | 
			
		||||
    batching::BatchingStrategy,
 | 
			
		||||
    component::{ComponentId, Tick},
 | 
			
		||||
    component::{ComponentId, Components, Tick},
 | 
			
		||||
    entity::Entity,
 | 
			
		||||
    prelude::FromWorld,
 | 
			
		||||
    query::{
 | 
			
		||||
@ -476,8 +476,8 @@ impl<D: QueryData, F: QueryFilter> QueryState<D, F> {
 | 
			
		||||
    /// You might end up with a mix of archetypes that only matched the original query + archetypes that only match
 | 
			
		||||
    /// the new [`QueryState`]. Most of the safe methods on [`QueryState`] call [`QueryState::update_archetypes`] internally, so this
 | 
			
		||||
    /// best used through a [`Query`](crate::system::Query).
 | 
			
		||||
    pub fn transmute<NewD: QueryData>(&self, world: &World) -> QueryState<NewD> {
 | 
			
		||||
        self.transmute_filtered::<NewD, ()>(world)
 | 
			
		||||
    pub fn transmute<NewD: QueryData>(&self, components: &Components) -> QueryState<NewD> {
 | 
			
		||||
        self.transmute_filtered::<NewD, ()>(components)
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /// Creates a new [`QueryState`] with the same underlying [`FilteredAccess`], matched tables and archetypes
 | 
			
		||||
@ -486,11 +486,11 @@ impl<D: QueryData, F: QueryFilter> QueryState<D, F> {
 | 
			
		||||
    /// Panics if `NewD` or `NewF` require accesses that this query does not have.
 | 
			
		||||
    pub fn transmute_filtered<NewD: QueryData, NewF: QueryFilter>(
 | 
			
		||||
        &self,
 | 
			
		||||
        world: &World,
 | 
			
		||||
        components: &Components,
 | 
			
		||||
    ) -> QueryState<NewD, NewF> {
 | 
			
		||||
        let mut component_access = FilteredAccess::default();
 | 
			
		||||
        let mut fetch_state = NewD::get_state(world).expect("Could not create fetch_state, Please initialize all referenced components before transmuting.");
 | 
			
		||||
        let filter_state = NewF::get_state(world).expect("Could not create filter_state, Please initialize all referenced components before transmuting.");
 | 
			
		||||
        let mut fetch_state = NewD::get_state(components).expect("Could not create fetch_state, Please initialize all referenced components before transmuting.");
 | 
			
		||||
        let filter_state = NewF::get_state(components).expect("Could not create filter_state, Please initialize all referenced components before transmuting.");
 | 
			
		||||
 | 
			
		||||
        NewD::set_access(&mut fetch_state, &self.component_access);
 | 
			
		||||
        NewD::update_component_access(&fetch_state, &mut component_access);
 | 
			
		||||
@ -544,10 +544,10 @@ impl<D: QueryData, F: QueryFilter> QueryState<D, F> {
 | 
			
		||||
    /// Will panic if `NewD` contains accesses not in `Q` or `OtherQ`.
 | 
			
		||||
    pub fn join<OtherD: QueryData, NewD: QueryData>(
 | 
			
		||||
        &self,
 | 
			
		||||
        world: &World,
 | 
			
		||||
        components: &Components,
 | 
			
		||||
        other: &QueryState<OtherD>,
 | 
			
		||||
    ) -> QueryState<NewD, ()> {
 | 
			
		||||
        self.join_filtered::<_, (), NewD, ()>(world, other)
 | 
			
		||||
        self.join_filtered::<_, (), NewD, ()>(components, other)
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /// Use this to combine two queries. The data accessed will be the intersection
 | 
			
		||||
@ -563,7 +563,7 @@ impl<D: QueryData, F: QueryFilter> QueryState<D, F> {
 | 
			
		||||
        NewF: QueryFilter,
 | 
			
		||||
    >(
 | 
			
		||||
        &self,
 | 
			
		||||
        world: &World,
 | 
			
		||||
        components: &Components,
 | 
			
		||||
        other: &QueryState<OtherD, OtherF>,
 | 
			
		||||
    ) -> QueryState<NewD, NewF> {
 | 
			
		||||
        if self.world_id != other.world_id {
 | 
			
		||||
@ -571,9 +571,9 @@ impl<D: QueryData, F: QueryFilter> QueryState<D, F> {
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        let mut component_access = FilteredAccess::default();
 | 
			
		||||
        let mut new_fetch_state = NewD::get_state(world)
 | 
			
		||||
        let mut new_fetch_state = NewD::get_state(components)
 | 
			
		||||
            .expect("Could not create fetch_state, Please initialize all referenced components before transmuting.");
 | 
			
		||||
        let new_filter_state = NewF::get_state(world)
 | 
			
		||||
        let new_filter_state = NewF::get_state(components)
 | 
			
		||||
            .expect("Could not create filter_state, Please initialize all referenced components before transmuting.");
 | 
			
		||||
 | 
			
		||||
        NewD::set_access(&mut new_fetch_state, &self.component_access);
 | 
			
		||||
@ -1779,7 +1779,7 @@ mod tests {
 | 
			
		||||
        world.spawn((A(1), B(0)));
 | 
			
		||||
 | 
			
		||||
        let query_state = world.query::<(&A, &B)>();
 | 
			
		||||
        let mut new_query_state = query_state.transmute::<&A>(&world);
 | 
			
		||||
        let mut new_query_state = query_state.transmute::<&A>(world.components());
 | 
			
		||||
        assert_eq!(new_query_state.iter(&world).len(), 1);
 | 
			
		||||
        let a = new_query_state.single(&world);
 | 
			
		||||
 | 
			
		||||
@ -1793,7 +1793,7 @@ mod tests {
 | 
			
		||||
        world.spawn((A(1), B(0), C(0)));
 | 
			
		||||
 | 
			
		||||
        let query_state = world.query_filtered::<(&A, &B), Without<C>>();
 | 
			
		||||
        let mut new_query_state = query_state.transmute::<&A>(&world);
 | 
			
		||||
        let mut new_query_state = query_state.transmute::<&A>(world.components());
 | 
			
		||||
        // even though we change the query to not have Without<C>, we do not get the component with C.
 | 
			
		||||
        let a = new_query_state.single(&world);
 | 
			
		||||
 | 
			
		||||
@ -1807,7 +1807,7 @@ mod tests {
 | 
			
		||||
        let entity = world.spawn(A(10)).id();
 | 
			
		||||
 | 
			
		||||
        let q = world.query::<()>();
 | 
			
		||||
        let mut q = q.transmute::<Entity>(&world);
 | 
			
		||||
        let mut q = q.transmute::<Entity>(world.components());
 | 
			
		||||
        assert_eq!(q.single(&world), entity);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
@ -1817,11 +1817,11 @@ mod tests {
 | 
			
		||||
        world.spawn(A(10));
 | 
			
		||||
 | 
			
		||||
        let q = world.query::<&A>();
 | 
			
		||||
        let mut new_q = q.transmute::<Ref<A>>(&world);
 | 
			
		||||
        let mut new_q = q.transmute::<Ref<A>>(world.components());
 | 
			
		||||
        assert!(new_q.single(&world).is_added());
 | 
			
		||||
 | 
			
		||||
        let q = world.query::<Ref<A>>();
 | 
			
		||||
        let _ = q.transmute::<&A>(&world);
 | 
			
		||||
        let _ = q.transmute::<&A>(world.components());
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    #[test]
 | 
			
		||||
@ -1830,8 +1830,8 @@ mod tests {
 | 
			
		||||
        world.spawn(A(0));
 | 
			
		||||
 | 
			
		||||
        let q = world.query::<&mut A>();
 | 
			
		||||
        let _ = q.transmute::<Ref<A>>(&world);
 | 
			
		||||
        let _ = q.transmute::<&A>(&world);
 | 
			
		||||
        let _ = q.transmute::<Ref<A>>(world.components());
 | 
			
		||||
        let _ = q.transmute::<&A>(world.components());
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    #[test]
 | 
			
		||||
@ -1840,7 +1840,7 @@ mod tests {
 | 
			
		||||
        world.spawn(A(0));
 | 
			
		||||
 | 
			
		||||
        let q: QueryState<EntityMut<'_>> = world.query::<EntityMut>();
 | 
			
		||||
        let _ = q.transmute::<EntityRef>(&world);
 | 
			
		||||
        let _ = q.transmute::<EntityRef>(world.components());
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    #[test]
 | 
			
		||||
@ -1849,8 +1849,8 @@ mod tests {
 | 
			
		||||
        world.spawn((A(0), B(0)));
 | 
			
		||||
 | 
			
		||||
        let query_state = world.query::<(Option<&A>, &B)>();
 | 
			
		||||
        let _ = query_state.transmute::<Option<&A>>(&world);
 | 
			
		||||
        let _ = query_state.transmute::<&B>(&world);
 | 
			
		||||
        let _ = query_state.transmute::<Option<&A>>(world.components());
 | 
			
		||||
        let _ = query_state.transmute::<&B>(world.components());
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    #[test]
 | 
			
		||||
@ -1864,7 +1864,7 @@ mod tests {
 | 
			
		||||
        world.spawn(A(0));
 | 
			
		||||
 | 
			
		||||
        let query_state = world.query::<&A>();
 | 
			
		||||
        let mut _new_query_state = query_state.transmute::<(&A, &B)>(&world);
 | 
			
		||||
        let mut _new_query_state = query_state.transmute::<(&A, &B)>(world.components());
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    #[test]
 | 
			
		||||
@ -1876,7 +1876,7 @@ mod tests {
 | 
			
		||||
        world.spawn(A(0));
 | 
			
		||||
 | 
			
		||||
        let query_state = world.query::<&A>();
 | 
			
		||||
        let mut _new_query_state = query_state.transmute::<&mut A>(&world);
 | 
			
		||||
        let mut _new_query_state = query_state.transmute::<&mut A>(world.components());
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    #[test]
 | 
			
		||||
@ -1888,7 +1888,7 @@ mod tests {
 | 
			
		||||
        world.spawn(C(0));
 | 
			
		||||
 | 
			
		||||
        let query_state = world.query::<Option<&A>>();
 | 
			
		||||
        let mut new_query_state = query_state.transmute::<&A>(&world);
 | 
			
		||||
        let mut new_query_state = query_state.transmute::<&A>(world.components());
 | 
			
		||||
        let x = new_query_state.single(&world);
 | 
			
		||||
        assert_eq!(x.0, 1234);
 | 
			
		||||
    }
 | 
			
		||||
@ -1902,15 +1902,15 @@ mod tests {
 | 
			
		||||
        world.init_component::<A>();
 | 
			
		||||
 | 
			
		||||
        let q = world.query::<EntityRef>();
 | 
			
		||||
        let _ = q.transmute::<&A>(&world);
 | 
			
		||||
        let _ = q.transmute::<&A>(world.components());
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    #[test]
 | 
			
		||||
    fn can_transmute_filtered_entity() {
 | 
			
		||||
        let mut world = World::new();
 | 
			
		||||
        let entity = world.spawn((A(0), B(1))).id();
 | 
			
		||||
        let query =
 | 
			
		||||
            QueryState::<(Entity, &A, &B)>::new(&mut world).transmute::<FilteredEntityRef>(&world);
 | 
			
		||||
        let query = QueryState::<(Entity, &A, &B)>::new(&mut world)
 | 
			
		||||
            .transmute::<FilteredEntityRef>(world.components());
 | 
			
		||||
 | 
			
		||||
        let mut query = query;
 | 
			
		||||
        // Our result is completely untyped
 | 
			
		||||
@ -1927,7 +1927,7 @@ mod tests {
 | 
			
		||||
        let entity_a = world.spawn(A(0)).id();
 | 
			
		||||
 | 
			
		||||
        let mut query = QueryState::<(Entity, &A, Has<B>)>::new(&mut world)
 | 
			
		||||
            .transmute_filtered::<(Entity, Has<B>), Added<A>>(&world);
 | 
			
		||||
            .transmute_filtered::<(Entity, Has<B>), Added<A>>(world.components());
 | 
			
		||||
 | 
			
		||||
        assert_eq!((entity_a, false), query.single(&world));
 | 
			
		||||
 | 
			
		||||
@ -1947,7 +1947,7 @@ mod tests {
 | 
			
		||||
        let entity_a = world.spawn(A(0)).id();
 | 
			
		||||
 | 
			
		||||
        let mut detection_query = QueryState::<(Entity, &A)>::new(&mut world)
 | 
			
		||||
            .transmute_filtered::<Entity, Changed<A>>(&world);
 | 
			
		||||
            .transmute_filtered::<Entity, Changed<A>>(world.components());
 | 
			
		||||
 | 
			
		||||
        let mut change_query = QueryState::<&mut A>::new(&mut world);
 | 
			
		||||
        assert_eq!(entity_a, detection_query.single(&world));
 | 
			
		||||
@ -1970,7 +1970,7 @@ mod tests {
 | 
			
		||||
        world.init_component::<A>();
 | 
			
		||||
        world.init_component::<B>();
 | 
			
		||||
        let query = QueryState::<&A>::new(&mut world);
 | 
			
		||||
        let _new_query = query.transmute_filtered::<Entity, Changed<B>>(&world);
 | 
			
		||||
        let _new_query = query.transmute_filtered::<Entity, Changed<B>>(world.components());
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    #[test]
 | 
			
		||||
@ -1983,7 +1983,8 @@ mod tests {
 | 
			
		||||
 | 
			
		||||
        let query_1 = QueryState::<&A, Without<C>>::new(&mut world);
 | 
			
		||||
        let query_2 = QueryState::<&B, Without<C>>::new(&mut world);
 | 
			
		||||
        let mut new_query: QueryState<Entity, ()> = query_1.join_filtered(&world, &query_2);
 | 
			
		||||
        let mut new_query: QueryState<Entity, ()> =
 | 
			
		||||
            query_1.join_filtered(world.components(), &query_2);
 | 
			
		||||
 | 
			
		||||
        assert_eq!(new_query.single(&world), entity_ab);
 | 
			
		||||
    }
 | 
			
		||||
@ -1998,7 +1999,8 @@ mod tests {
 | 
			
		||||
 | 
			
		||||
        let query_1 = QueryState::<&A>::new(&mut world);
 | 
			
		||||
        let query_2 = QueryState::<&B, Without<C>>::new(&mut world);
 | 
			
		||||
        let mut new_query: QueryState<Entity, ()> = query_1.join_filtered(&world, &query_2);
 | 
			
		||||
        let mut new_query: QueryState<Entity, ()> =
 | 
			
		||||
            query_1.join_filtered(world.components(), &query_2);
 | 
			
		||||
 | 
			
		||||
        assert!(new_query.get(&world, entity_ab).is_ok());
 | 
			
		||||
        // should not be able to get entity with c.
 | 
			
		||||
@ -2014,7 +2016,7 @@ mod tests {
 | 
			
		||||
        world.init_component::<C>();
 | 
			
		||||
        let query_1 = QueryState::<&A>::new(&mut world);
 | 
			
		||||
        let query_2 = QueryState::<&B>::new(&mut world);
 | 
			
		||||
        let _query: QueryState<&C> = query_1.join(&world, &query_2);
 | 
			
		||||
        let _query: QueryState<&C> = query_1.join(world.components(), &query_2);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    #[test]
 | 
			
		||||
@ -2028,6 +2030,6 @@ mod tests {
 | 
			
		||||
        let mut world = World::new();
 | 
			
		||||
        let query_1 = QueryState::<&A, Without<C>>::new(&mut world);
 | 
			
		||||
        let query_2 = QueryState::<&B, Without<C>>::new(&mut world);
 | 
			
		||||
        let _: QueryState<Entity, Changed<C>> = query_1.join_filtered(&world, &query_2);
 | 
			
		||||
        let _: QueryState<Entity, Changed<C>> = query_1.join_filtered(world.components(), &query_2);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -1,6 +1,6 @@
 | 
			
		||||
use crate::{
 | 
			
		||||
    archetype::Archetype,
 | 
			
		||||
    component::{ComponentId, Tick},
 | 
			
		||||
    component::{ComponentId, Components, Tick},
 | 
			
		||||
    entity::Entity,
 | 
			
		||||
    query::FilteredAccess,
 | 
			
		||||
    storage::{Table, TableRow},
 | 
			
		||||
@ -130,8 +130,8 @@ pub unsafe trait WorldQuery {
 | 
			
		||||
    fn init_state(world: &mut World) -> Self::State;
 | 
			
		||||
 | 
			
		||||
    /// Attempts to initialize a [`State`](WorldQuery::State) for this [`WorldQuery`] type using read-only
 | 
			
		||||
    /// access to the [`World`].
 | 
			
		||||
    fn get_state(world: &World) -> Option<Self::State>;
 | 
			
		||||
    /// access to [`Components`].
 | 
			
		||||
    fn get_state(components: &Components) -> Option<Self::State>;
 | 
			
		||||
 | 
			
		||||
    /// Returns `true` if this query matches a set of components. Otherwise, returns `false`.
 | 
			
		||||
    ///
 | 
			
		||||
@ -212,13 +212,13 @@ macro_rules! impl_tuple_world_query {
 | 
			
		||||
                let ($($name,)*) = state;
 | 
			
		||||
                $($name::update_component_access($name, _access);)*
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            fn init_state(_world: &mut World) -> Self::State {
 | 
			
		||||
                ($($name::init_state(_world),)*)
 | 
			
		||||
            #[allow(unused_variables)]
 | 
			
		||||
            fn init_state(world: &mut World) -> Self::State {
 | 
			
		||||
                ($($name::init_state(world),)*)
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            fn get_state(_world: &World) -> Option<Self::State> {
 | 
			
		||||
                Some(($($name::get_state(_world)?,)*))
 | 
			
		||||
            #[allow(unused_variables)]
 | 
			
		||||
            fn get_state(components: &Components) -> Option<Self::State> {
 | 
			
		||||
                Some(($($name::get_state(components)?,)*))
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            fn matches_component_set(state: &Self::State, _set_contains_id: &impl Fn(ComponentId) -> bool) -> bool {
 | 
			
		||||
 | 
			
		||||
@ -1368,12 +1368,8 @@ impl<'w, 's, D: QueryData, F: QueryFilter> Query<'w, 's, D, F> {
 | 
			
		||||
    pub fn transmute_lens_filtered<NewD: QueryData, NewF: QueryFilter>(
 | 
			
		||||
        &mut self,
 | 
			
		||||
    ) -> QueryLens<'_, NewD, NewF> {
 | 
			
		||||
        // SAFETY:
 | 
			
		||||
        // - We have exclusive access to the query
 | 
			
		||||
        // - `self` has correctly captured its access
 | 
			
		||||
        // - Access is checked to be a subset of the query's access when the state is created.
 | 
			
		||||
        let world = unsafe { self.world.world() };
 | 
			
		||||
        let state = self.state.transmute_filtered::<NewD, NewF>(world);
 | 
			
		||||
        let components = self.world.components();
 | 
			
		||||
        let state = self.state.transmute_filtered::<NewD, NewF>(components);
 | 
			
		||||
        QueryLens {
 | 
			
		||||
            world: self.world,
 | 
			
		||||
            state,
 | 
			
		||||
@ -1464,14 +1460,10 @@ impl<'w, 's, D: QueryData, F: QueryFilter> Query<'w, 's, D, F> {
 | 
			
		||||
        &mut self,
 | 
			
		||||
        other: &mut Query<OtherD, OtherF>,
 | 
			
		||||
    ) -> QueryLens<'_, NewD, NewF> {
 | 
			
		||||
        // SAFETY:
 | 
			
		||||
        // - The queries have correctly captured their access.
 | 
			
		||||
        // - We have exclusive access to both queries.
 | 
			
		||||
        // - Access for QueryLens is checked when state is created.
 | 
			
		||||
        let world = unsafe { self.world.world() };
 | 
			
		||||
        let components = self.world.components();
 | 
			
		||||
        let state = self
 | 
			
		||||
            .state
 | 
			
		||||
            .join_filtered::<OtherD, OtherF, NewD, NewF>(world, other.state);
 | 
			
		||||
            .join_filtered::<OtherD, OtherF, NewD, NewF>(components, other.state);
 | 
			
		||||
        QueryLens {
 | 
			
		||||
            world: self.world,
 | 
			
		||||
            state,
 | 
			
		||||
 | 
			
		||||
		Loading…
	
		Reference in New Issue
	
	Block a user