From 9d453530fac9202691c797184ad0b220b2ea37b3 Mon Sep 17 00:00:00 2001 From: Carter Anderson Date: Sun, 15 Aug 2021 20:51:53 +0000 Subject: [PATCH] System Param Lifetime Split (#2605) # Objective Enable using exact World lifetimes during read-only access . This is motivated by the new renderer's need to allow read-only world-only queries to outlive the query itself (but still be constrained by the world lifetime). For example: https://github.com/bevyengine/bevy/blob/115b170d1f11a91146bb6d6e9684dceb8b21f786/pipelined/bevy_pbr2/src/render/mod.rs#L774 ## Solution Split out SystemParam state and world lifetimes and pipe those lifetimes up to read-only Query ops (and add into_inner for Res). According to every safety test I've run so far (except one), this is safe (see the temporary safety test commit). Note that changing the mutable variants to the new lifetimes would allow aliased mutable pointers (try doing that to see how it affects the temporary safety tests). The new state lifetime on SystemParam does make `#[derive(SystemParam)]` more cumbersome (the current impl requires PhantomData if you don't use both lifetimes). We can make this better by detecting whether or not a lifetime is used in the derive and adjusting accordingly, but that should probably be done in its own pr. ## Why is this a draft? The new lifetimes break QuerySet safety in one very specific case (see the query_set system in system_safety_test). We need to solve this before we can use the lifetimes given. This is due to the fact that QuerySet is just a wrapper over Query, which now relies on world lifetimes instead of `&self` lifetimes to prevent aliasing (but in systems, each Query has its own implied lifetime, not a centralized world lifetime). I believe the fix is to rewrite QuerySet to have its own World lifetime (and own the internal reference). This will complicate the impl a bit, but I think it is doable. I'm curious if anyone else has better ideas. Personally, I think these new lifetimes need to happen. We've gotta have a way to directly tie read-only World queries to the World lifetime. The new renderer is the first place this has come up, but I doubt it will be the last. Worst case scenario we can come up with a second `WorldLifetimeQuery` parameter to enable these read-only scenarios, but I'd rather not add another type to the type zoo. --- crates/bevy_ecs/macros/src/lib.rs | 57 ++--- crates/bevy_ecs/src/event.rs | 16 +- crates/bevy_ecs/src/query/state.rs | 24 +- crates/bevy_ecs/src/system/commands/mod.rs | 24 +- crates/bevy_ecs/src/system/function_system.rs | 21 +- crates/bevy_ecs/src/system/mod.rs | 220 +++++++++++++++++- crates/bevy_ecs/src/system/query.rs | 58 ++--- crates/bevy_ecs/src/system/system_param.rs | 174 +++++++------- crates/bevy_render/src/camera/camera.rs | 9 +- crates/bevy_render/src/draw.rs | 20 +- crates/bevy_render/src/mesh/mesh.rs | 11 +- .../nodes/render_resources_node.rs | 33 ++- crates/bevy_render/src/wireframe/mod.rs | 12 +- crates/bevy_scene/src/command.rs | 4 +- crates/bevy_text/src/text2d.rs | 10 +- .../src/hierarchy/child_builder.rs | 12 +- .../bevy_transform/src/hierarchy/hierarchy.rs | 2 +- crates/bevy_ui/src/widget/text.rs | 10 +- examples/ecs/system_param.rs | 8 +- examples/game/alien_cake_addict.rs | 12 +- 20 files changed, 481 insertions(+), 256 deletions(-) diff --git a/crates/bevy_ecs/macros/src/lib.rs b/crates/bevy_ecs/macros/src/lib.rs index 9755e92637..8371de3e4b 100644 --- a/crates/bevy_ecs/macros/src/lib.rs +++ b/crates/bevy_ecs/macros/src/lib.rs @@ -9,8 +9,8 @@ use syn::{ parse_macro_input, punctuated::Punctuated, token::Comma, - Data, DataStruct, DeriveInput, Field, Fields, GenericParam, Ident, Index, Lifetime, LitInt, - Path, Result, Token, + Data, DataStruct, DeriveInput, Field, Fields, GenericParam, Ident, Index, LitInt, Path, Result, + Token, }; struct AllTuples { @@ -176,36 +176,26 @@ fn get_idents(fmt_string: fn(usize) -> String, count: usize) -> Vec { .collect::>() } -fn get_lifetimes(fmt_string: fn(usize) -> String, count: usize) -> Vec { - (0..count) - .map(|i| Lifetime::new(&fmt_string(i), Span::call_site())) - .collect::>() -} - #[proc_macro] pub fn impl_query_set(_input: TokenStream) -> TokenStream { let mut tokens = TokenStream::new(); let max_queries = 4; let queries = get_idents(|i| format!("Q{}", i), max_queries); let filters = get_idents(|i| format!("F{}", i), max_queries); - let lifetimes = get_lifetimes(|i| format!("'q{}", i), max_queries); - let mut query_fns = Vec::new(); let mut query_fn_muts = Vec::new(); for i in 0..max_queries { let query = &queries[i]; let filter = &filters[i]; - let lifetime = &lifetimes[i]; let fn_name = Ident::new(&format!("q{}", i), Span::call_site()); - let fn_name_mut = Ident::new(&format!("q{}_mut", i), Span::call_site()); let index = Index::from(i); - query_fns.push(quote! { - pub fn #fn_name(&self) -> &Query<#lifetime, #query, #filter> { - &self.0.#index - } - }); query_fn_muts.push(quote! { - pub fn #fn_name_mut(&mut self) -> &mut Query<#lifetime, #query, #filter> { - &mut self.0.#index + pub fn #fn_name(&mut self) -> Query<'_, '_, #query, #filter> { + // SAFE: systems run without conflicts with other systems. + // Conflicting queries in QuerySet are not accessible at the same time + // QuerySets are guaranteed to not conflict with other SystemParams + unsafe { + Query::new(self.world, &self.query_states.#index, self.last_change_tick, self.change_tick) + } } }); } @@ -213,11 +203,9 @@ pub fn impl_query_set(_input: TokenStream) -> TokenStream { for query_count in 1..=max_queries { let query = &queries[0..query_count]; let filter = &filters[0..query_count]; - let lifetime = &lifetimes[0..query_count]; - let query_fn = &query_fns[0..query_count]; let query_fn_mut = &query_fn_muts[0..query_count]; tokens.extend(TokenStream::from(quote! { - impl<#(#lifetime,)* #(#query: WorldQuery + 'static,)* #(#filter: WorldQuery + 'static,)*> SystemParam for QuerySet<(#(Query<#lifetime, #query, #filter>,)*)> + impl<'w, 's, #(#query: WorldQuery + 'static,)* #(#filter: WorldQuery + 'static,)*> SystemParam for QuerySet<'w, 's, (#(QueryState<#query, #filter>,)*)> where #(#filter::Fetch: FilterFetch,)* { type Fetch = QuerySetState<(#(QueryState<#query, #filter>,)*)>; @@ -270,27 +258,30 @@ pub fn impl_query_set(_input: TokenStream) -> TokenStream { fn default_config() {} } - impl<'a, #(#query: WorldQuery + 'static,)* #(#filter: WorldQuery + 'static,)*> SystemParamFetch<'a> for QuerySetState<(#(QueryState<#query, #filter>,)*)> + impl<'w, 's, #(#query: WorldQuery + 'static,)* #(#filter: WorldQuery + 'static,)*> SystemParamFetch<'w, 's> for QuerySetState<(#(QueryState<#query, #filter>,)*)> where #(#filter::Fetch: FilterFetch,)* { - type Item = QuerySet<(#(Query<'a, #query, #filter>,)*)>; + type Item = QuerySet<'w, 's, (#(QueryState<#query, #filter>,)*)>; #[inline] unsafe fn get_param( - state: &'a mut Self, + state: &'s mut Self, system_meta: &SystemMeta, - world: &'a World, + world: &'w World, change_tick: u32, ) -> Self::Item { - let (#(#query,)*) = &state.0; - QuerySet((#(Query::new(world, #query, system_meta.last_change_tick, change_tick),)*)) + QuerySet { + query_states: &state.0, + world, + last_change_tick: system_meta.last_change_tick, + change_tick, + } } } - impl<#(#lifetime,)* #(#query: WorldQuery,)* #(#filter: WorldQuery,)*> QuerySet<(#(Query<#lifetime, #query, #filter>,)*)> + impl<'w, 's, #(#query: WorldQuery,)* #(#filter: WorldQuery,)*> QuerySet<'w, 's, (#(QueryState<#query, #filter>,)*)> where #(#filter::Fetch: FilterFetch,)* { - #(#query_fn)* #(#query_fn_mut)* } })); @@ -415,12 +406,12 @@ pub fn derive_system_param(input: TokenStream) -> TokenStream { } } - impl #impl_generics #path::system::SystemParamFetch<'a> for #fetch_struct_name <(#(<#field_types as #path::system::SystemParam>::Fetch,)*), #punctuated_generic_idents> { + impl #impl_generics #path::system::SystemParamFetch<'w, 's> for #fetch_struct_name <(#(<#field_types as #path::system::SystemParam>::Fetch,)*), #punctuated_generic_idents> { type Item = #struct_name#ty_generics; unsafe fn get_param( - state: &'a mut Self, + state: &'s mut Self, system_meta: &#path::system::SystemMeta, - world: &'a #path::world::World, + world: &'w #path::world::World, change_tick: u32, ) -> Self::Item { #struct_name { diff --git a/crates/bevy_ecs/src/event.rs b/crates/bevy_ecs/src/event.rs index 0260da3a57..f088b27f10 100644 --- a/crates/bevy_ecs/src/event.rs +++ b/crates/bevy_ecs/src/event.rs @@ -151,18 +151,20 @@ fn map_instance_event(event_instance: &EventInstance) -> &T { /// Reads events of type `T` in order and tracks which events have already been read. #[derive(SystemParam)] -pub struct EventReader<'a, T: Component> { - last_event_count: Local<'a, (usize, PhantomData)>, - events: Res<'a, Events>, +pub struct EventReader<'w, 's, T: Component> { + last_event_count: Local<'s, (usize, PhantomData)>, + events: Res<'w, Events>, } /// Sends events of type `T`. #[derive(SystemParam)] -pub struct EventWriter<'a, T: Component> { - events: ResMut<'a, Events>, +pub struct EventWriter<'w, 's, T: Component> { + events: ResMut<'w, Events>, + #[system_param(ignore)] + marker: PhantomData<&'s usize>, } -impl<'a, T: Component> EventWriter<'a, T> { +impl<'w, 's, T: Component> EventWriter<'w, 's, T> { pub fn send(&mut self, event: T) { self.events.send(event); } @@ -252,7 +254,7 @@ fn internal_event_reader<'a, T>( } } -impl<'a, T: Component> EventReader<'a, T> { +impl<'w, 's, T: Component> EventReader<'w, 's, T> { /// Iterates over the events this EventReader has not seen yet. This updates the EventReader's /// event counter, which means subsequent event reads will not include events that happened /// before now. diff --git a/crates/bevy_ecs/src/query/state.rs b/crates/bevy_ecs/src/query/state.rs index 6349d3101b..df7cba0eb1 100644 --- a/crates/bevy_ecs/src/query/state.rs +++ b/crates/bevy_ecs/src/query/state.rs @@ -117,11 +117,11 @@ where } #[inline] - pub fn get<'w>( - &mut self, + pub fn get<'w, 's>( + &'s mut self, world: &'w World, entity: Entity, - ) -> Result<>::Item, QueryEntityError> + ) -> Result<>::Item, QueryEntityError> where Q::Fetch: ReadOnlyFetch, { @@ -130,11 +130,11 @@ where } #[inline] - pub fn get_mut<'w>( - &mut self, + pub fn get_mut<'w, 's>( + &'s mut self, world: &'w mut World, entity: Entity, - ) -> Result<>::Item, QueryEntityError> { + ) -> Result<>::Item, QueryEntityError> { // SAFETY: query has unique world access unsafe { self.get_unchecked(world, entity) } } @@ -144,11 +144,11 @@ where /// This does not check for mutable query correctness. To be safe, make sure mutable queries /// have unique access to the components they query. #[inline] - pub unsafe fn get_unchecked<'w>( - &mut self, + pub unsafe fn get_unchecked<'w, 's>( + &'s mut self, world: &'w World, entity: Entity, - ) -> Result<>::Item, QueryEntityError> { + ) -> Result<>::Item, QueryEntityError> { self.validate_world_and_update_archetypes(world); self.get_unchecked_manual( world, @@ -161,13 +161,13 @@ where /// # Safety /// This does not check for mutable query correctness. To be safe, make sure mutable queries /// have unique access to the components they query. - pub unsafe fn get_unchecked_manual<'w>( - &self, + pub unsafe fn get_unchecked_manual<'w, 's>( + &'s self, world: &'w World, entity: Entity, last_change_tick: u32, change_tick: u32, - ) -> Result<>::Item, QueryEntityError> { + ) -> Result<>::Item, QueryEntityError> { let location = world .entities .get(entity) diff --git a/crates/bevy_ecs/src/system/commands/mod.rs b/crates/bevy_ecs/src/system/commands/mod.rs index 0488b09e4f..97304959fc 100644 --- a/crates/bevy_ecs/src/system/commands/mod.rs +++ b/crates/bevy_ecs/src/system/commands/mod.rs @@ -16,14 +16,14 @@ pub trait Command: Send + Sync + 'static { } /// A list of commands that will be run to modify a [`World`]. -pub struct Commands<'a> { - queue: &'a mut CommandQueue, - entities: &'a Entities, +pub struct Commands<'w, 's> { + queue: &'s mut CommandQueue, + entities: &'w Entities, } -impl<'a> Commands<'a> { +impl<'w, 's> Commands<'w, 's> { /// Create a new `Commands` from a queue and a world. - pub fn new(queue: &'a mut CommandQueue, world: &'a World) -> Self { + pub fn new(queue: &'s mut CommandQueue, world: &'w World) -> Self { Self { queue, entities: world.entities(), @@ -50,7 +50,7 @@ impl<'a> Commands<'a> { /// } /// # example_system.system(); /// ``` - pub fn spawn(&mut self) -> EntityCommands<'a, '_> { + pub fn spawn<'a>(&'a mut self) -> EntityCommands<'w, 's, 'a> { let entity = self.entities.reserve_entity(); EntityCommands { entity, @@ -98,7 +98,7 @@ impl<'a> Commands<'a> { /// } /// # example_system.system(); /// ``` - pub fn spawn_bundle<'b, T: Bundle>(&'b mut self, bundle: T) -> EntityCommands<'a, 'b> { + pub fn spawn_bundle<'a, T: Bundle>(&'a mut self, bundle: T) -> EntityCommands<'w, 's, 'a> { let mut e = self.spawn(); e.insert_bundle(bundle); e @@ -123,7 +123,7 @@ impl<'a> Commands<'a> { /// } /// # example_system.system(); /// ``` - pub fn entity(&mut self, entity: Entity) -> EntityCommands<'a, '_> { + pub fn entity<'a>(&'a mut self, entity: Entity) -> EntityCommands<'w, 's, 'a> { EntityCommands { entity, commands: self, @@ -159,12 +159,12 @@ impl<'a> Commands<'a> { } /// A list of commands that will be run to modify an [`Entity`]. -pub struct EntityCommands<'a, 'b> { +pub struct EntityCommands<'w, 's, 'a> { entity: Entity, - commands: &'b mut Commands<'a>, + commands: &'a mut Commands<'w, 's>, } -impl<'a, 'b> EntityCommands<'a, 'b> { +impl<'w, 's, 'a> EntityCommands<'w, 's, 'a> { /// Retrieves the current entity's unique [`Entity`] id. #[inline] pub fn id(&self) -> Entity { @@ -252,7 +252,7 @@ impl<'a, 'b> EntityCommands<'a, 'b> { } /// Returns the underlying `[Commands]`. - pub fn commands(&mut self) -> &mut Commands<'a> { + pub fn commands(&mut self) -> &mut Commands<'w, 's> { self.commands } } diff --git a/crates/bevy_ecs/src/system/function_system.rs b/crates/bevy_ecs/src/system/function_system.rs index bb85fc8bbc..c37653c078 100644 --- a/crates/bevy_ecs/src/system/function_system.rs +++ b/crates/bevy_ecs/src/system/function_system.rs @@ -87,7 +87,10 @@ impl SystemState { /// Retrieve the [`SystemParam`] values. This can only be called when all parameters are read-only. #[inline] - pub fn get<'a>(&'a mut self, world: &'a World) -> >::Item + pub fn get<'w, 's>( + &'s mut self, + world: &'w World, + ) -> >::Item where Param::Fetch: ReadOnlySystemParamFetch, { @@ -98,10 +101,10 @@ impl SystemState { /// Retrieve the mutable [`SystemParam`] values. #[inline] - pub fn get_mut<'a>( - &'a mut self, - world: &'a mut World, - ) -> >::Item { + pub fn get_mut<'w, 's>( + &'s mut self, + world: &'w mut World, + ) -> >::Item { self.validate_world_and_update_archetypes(world); // SAFE: World is uniquely borrowed and matches the World this SystemState was created with. unsafe { self.get_unchecked_manual(world) } @@ -142,10 +145,10 @@ impl SystemState { /// access is safe in the context of global [`World`] access. The passed-in [`World`] _must_ be the [`World`] the [`SystemState`] was /// created with. #[inline] - pub unsafe fn get_unchecked_manual<'a>( - &'a mut self, - world: &'a World, - ) -> >::Item { + pub unsafe fn get_unchecked_manual<'w, 's>( + &'s mut self, + world: &'w World, + ) -> >::Item { let change_tick = world.increment_change_tick(); let param = ::get_param( &mut self.param_state, diff --git a/crates/bevy_ecs/src/system/mod.rs b/crates/bevy_ecs/src/system/mod.rs index 92b03c1f4e..8f0172af97 100644 --- a/crates/bevy_ecs/src/system/mod.rs +++ b/crates/bevy_ecs/src/system/mod.rs @@ -24,7 +24,7 @@ mod tests { bundle::Bundles, component::Components, entity::{Entities, Entity}, - query::{Added, Changed, Or, With, Without}, + query::{Added, Changed, Or, QueryState, With, Without}, schedule::{Schedule, Stage, SystemStage}, system::{ ConfigurableSystem, IntoExclusiveSystem, IntoSystem, Local, Query, QuerySet, @@ -131,9 +131,9 @@ mod tests { // Regression test for issue #762 fn query_system( mut ran: ResMut, - set: QuerySet<( - Query<(), Or<(Changed, Changed)>>, - Query<(), Or<(Added, Added)>>, + mut set: QuerySet<( + QueryState<(), Or<(Changed, Changed)>>, + QueryState<(), Or<(Added, Added)>>, )>, ) { let changed = set.q0().iter().count(); @@ -236,7 +236,7 @@ mod tests { #[test] fn query_set_system() { - fn sys(mut _set: QuerySet<(Query<&mut A>, Query<&A>)>) {} + fn sys(mut _set: QuerySet<(QueryState<&mut A>, QueryState<&A>)>) {} let mut world = World::default(); run_system(&mut world, sys); } @@ -244,7 +244,7 @@ mod tests { #[test] #[should_panic] fn conflicting_query_with_query_set_system() { - fn sys(_query: Query<&mut A>, _set: QuerySet<(Query<&mut A>, Query<&B>)>) {} + fn sys(_query: Query<&mut A>, _set: QuerySet<(QueryState<&mut A>, QueryState<&B>)>) {} let mut world = World::default(); run_system(&mut world, sys); @@ -253,7 +253,11 @@ mod tests { #[test] #[should_panic] fn conflicting_query_sets_system() { - fn sys(_set_1: QuerySet<(Query<&mut A>,)>, _set_2: QuerySet<(Query<&mut A>, Query<&B>)>) {} + fn sys( + _set_1: QuerySet<(QueryState<&mut A>,)>, + _set_2: QuerySet<(QueryState<&mut A>, QueryState<&B>)>, + ) { + } let mut world = World::default(); run_system(&mut world, sys); @@ -520,8 +524,11 @@ mod tests { world.insert_resource(A(42)); world.spawn().insert(B(7)); - let mut system_state: SystemState<(Res, Query<&B>, QuerySet<(Query<&C>, Query<&D>)>)> = - SystemState::new(&mut world); + let mut system_state: SystemState<( + Res, + Query<&B>, + QuerySet<(QueryState<&C>, QueryState<&D>)>, + )> = SystemState::new(&mut world); let (a, query, _) = system_state.get(&world); assert_eq!(*a, A(42), "returned resource matches initial value"); assert_eq!( @@ -624,4 +631,199 @@ mod tests { ); } } + + /// this test exists to show that read-only world-only queries can return data that lives as long as 'world + #[test] + #[allow(unused)] + fn long_life_test() { + struct Holder<'w> { + value: &'w A, + } + + struct State { + state: SystemState>, + state_q: SystemState>, + } + + impl State { + fn hold_res<'w>(&mut self, world: &'w World) -> Holder<'w> { + let a = self.state.get(world); + Holder { + value: a.into_inner(), + } + } + fn hold_component<'w>(&mut self, world: &'w World, entity: Entity) -> Holder<'w> { + let q = self.state_q.get(world); + let a = q.get(entity).unwrap(); + Holder { value: a } + } + fn hold_components<'w>(&mut self, world: &'w World) -> Vec> { + let mut components = Vec::new(); + let q = self.state_q.get(world); + for a in q.iter() { + components.push(Holder { value: a }); + } + components + } + } + } } + +/// ```compile_fail +/// use bevy_ecs::prelude::*; +/// struct A(usize); +/// fn system(mut query: Query<&mut A>, e: Res) { +/// let mut iter = query.iter_mut(); +/// let a = &mut *iter.next().unwrap(); +/// +/// let mut iter2 = query.iter_mut(); +/// let b = &mut *iter2.next().unwrap(); +/// +/// // this should fail to compile +/// println!("{}", a.0); +/// } +/// ``` +#[allow(unused)] +#[cfg(doc)] +fn system_query_iter_lifetime_safety_test() {} + +/// ```compile_fail +/// use bevy_ecs::prelude::*; +/// struct A(usize); +/// fn system(mut query: Query<&mut A>, e: Res) { +/// let mut a1 = query.get_mut(*e).unwrap(); +/// let mut a2 = query.get_mut(*e).unwrap(); +/// // this should fail to compile +/// println!("{} {}", a1.0, a2.0); +/// } +/// ``` +#[allow(unused)] +#[cfg(doc)] +fn system_query_get_lifetime_safety_test() {} + +/// ```compile_fail +/// use bevy_ecs::prelude::*; +/// struct A(usize); +/// fn query_set(mut queries: QuerySet<(QueryState<&mut A>, QueryState<&A>)>, e: Res) { +/// let mut q2 = queries.q0(); +/// let mut iter2 = q2.iter_mut(); +/// let mut b = iter2.next().unwrap(); +/// +/// let q1 = queries.q1(); +/// let mut iter = q1.iter(); +/// let a = &*iter.next().unwrap(); +/// +/// // this should fail to compile +/// b.0 = a.0 +/// } +/// ``` +#[allow(unused)] +#[cfg(doc)] +fn system_query_set_iter_lifetime_safety_test() {} + +/// ```compile_fail +/// use bevy_ecs::prelude::*; +/// struct A(usize); +/// fn query_set(mut queries: QuerySet<(QueryState<&mut A>, QueryState<&A>)>, e: Res) { +/// let q1 = queries.q1(); +/// let mut iter = q1.iter(); +/// let a = &*iter.next().unwrap(); +/// +/// let mut q2 = queries.q0(); +/// let mut iter2 = q2.iter_mut(); +/// let mut b = iter2.next().unwrap(); +/// +/// // this should fail to compile +/// b.0 = a.0; +/// } +/// ``` +#[allow(unused)] +#[cfg(doc)] +fn system_query_set_iter_flip_lifetime_safety_test() {} + +/// ```compile_fail +/// use bevy_ecs::prelude::*; +/// struct A(usize); +/// fn query_set(mut queries: QuerySet<(QueryState<&mut A>, QueryState<&A>)>, e: Res) { +/// let mut q2 = queries.q0(); +/// let mut b = q2.get_mut(*e).unwrap(); +/// +/// let q1 = queries.q1(); +/// let a = q1.get(*e).unwrap(); +/// +/// // this should fail to compile +/// b.0 = a.0 +/// } +/// ``` +#[allow(unused)] +#[cfg(doc)] +fn system_query_set_get_lifetime_safety_test() {} + +/// ```compile_fail +/// use bevy_ecs::prelude::*; +/// struct A(usize); +/// fn query_set(mut queries: QuerySet<(QueryState<&mut A>, QueryState<&A>)>, e: Res) { +/// let q1 = queries.q1(); +/// let a = q1.get(*e).unwrap(); +/// +/// let mut q2 = queries.q0(); +/// let mut b = q2.get_mut(*e).unwrap(); +/// // this should fail to compile +/// b.0 = a.0 +/// } +/// ``` +#[allow(unused)] +#[cfg(doc)] +fn system_query_set_get_flip_lifetime_safety_test() {} + +/// ```compile_fail +/// use bevy_ecs::prelude::*; +/// use bevy_ecs::system::SystemState; +/// struct A(usize); +/// struct B(usize); +/// struct State { +/// state_r: SystemState>, +/// state_w: SystemState>, +/// } +/// +/// impl State { +/// fn get_component<'w>(&mut self, world: &'w mut World, entity: Entity) { +/// let q1 = self.state_r.get(&world); +/// let a1 = q1.get(entity).unwrap(); +/// +/// let mut q2 = self.state_w.get_mut(world); +/// let a2 = q2.get_mut(entity).unwrap(); +/// +/// // this should fail to compile +/// println!("{}", a1.0); +/// } +/// } +/// ``` +#[allow(unused)] +#[cfg(doc)] +fn system_state_get_lifetime_safety_test() {} + +/// ```compile_fail +/// use bevy_ecs::prelude::*; +/// use bevy_ecs::system::SystemState; +/// struct A(usize); +/// struct B(usize); +/// struct State { +/// state_r: SystemState>, +/// state_w: SystemState>, +/// } +/// +/// impl State { +/// fn get_components<'w>(&mut self, world: &'w mut World) { +/// let q1 = self.state_r.get(&world); +/// let a1 = q1.iter().next().unwrap(); +/// let mut q2 = self.state_w.get_mut(world); +/// let a2 = q2.iter_mut().next().unwrap(); +/// // this should fail to compile +/// println!("{}", a1.0); +/// } +/// } +/// ``` +#[allow(unused)] +#[cfg(doc)] +fn system_state_iter_lifetime_safety_test() {} diff --git a/crates/bevy_ecs/src/system/query.rs b/crates/bevy_ecs/src/system/query.rs index 05ff84a798..e550ac6fa0 100644 --- a/crates/bevy_ecs/src/system/query.rs +++ b/crates/bevy_ecs/src/system/query.rs @@ -107,17 +107,17 @@ use thiserror::Error; /// /// This touches all the basics of queries, make sure to check out all the [`WorldQueries`](WorldQuery) /// bevy has to offer. -pub struct Query<'w, Q: WorldQuery, F: WorldQuery = ()> +pub struct Query<'world, 'state, Q: WorldQuery, F: WorldQuery = ()> where F::Fetch: FilterFetch, { - pub(crate) world: &'w World, - pub(crate) state: &'w QueryState, + pub(crate) world: &'world World, + pub(crate) state: &'state QueryState, pub(crate) last_change_tick: u32, pub(crate) change_tick: u32, } -impl<'w, Q: WorldQuery, F: WorldQuery> Query<'w, Q, F> +impl<'w, 's, Q: WorldQuery, F: WorldQuery> Query<'w, 's, Q, F> where F::Fetch: FilterFetch, { @@ -130,7 +130,7 @@ where #[inline] pub(crate) unsafe fn new( world: &'w World, - state: &'w QueryState, + state: &'s QueryState, last_change_tick: u32, change_tick: u32, ) -> Self { @@ -146,7 +146,7 @@ where /// /// This can only be called for read-only queries, see [`Self::iter_mut`] for write-queries. #[inline] - pub fn iter(&self) -> QueryIter<'_, '_, Q, F> + pub fn iter(&'s self) -> QueryIter<'w, 's, Q, F> where Q::Fetch: ReadOnlyFetch, { @@ -158,6 +158,17 @@ where } } + /// Returns an [`Iterator`] over the query results. + #[inline] + pub fn iter_mut(&mut self) -> QueryIter<'_, '_, Q, F> { + // SAFE: system runs without conflicts with other systems. + // same-system queries have runtime borrow checks when they conflict + unsafe { + self.state + .iter_unchecked_manual(self.world, self.last_change_tick, self.change_tick) + } + } + /// Returns an [`Iterator`] over all possible combinations of `K` query results without repetition. /// This can only be called for read-only queries /// @@ -181,17 +192,6 @@ where } } - /// Returns an [`Iterator`] over the query results. - #[inline] - pub fn iter_mut(&mut self) -> QueryIter<'_, '_, Q, F> { - // SAFE: system runs without conflicts with other systems. - // same-system queries have runtime borrow checks when they conflict - unsafe { - self.state - .iter_unchecked_manual(self.world, self.last_change_tick, self.change_tick) - } - } - /// Iterates over all possible combinations of `K` query results without repetition. /// /// The returned value is not an `Iterator`, because that would lead to aliasing of mutable references. @@ -266,7 +266,7 @@ where /// /// This can only be called for read-only queries, see [`Self::for_each_mut`] for write-queries. #[inline] - pub fn for_each<'s>(&'s self, f: impl FnMut(>::Item)) + pub fn for_each(&'s self, f: impl FnMut(>::Item)) where Q::Fetch: ReadOnlyFetch, { @@ -285,7 +285,7 @@ where /// Runs `f` on each query result. This is faster than the equivalent iter() method, but cannot /// be chained like a normal [`Iterator`]. #[inline] - pub fn for_each_mut<'s>(&'s mut self, f: impl FnMut(>::Item)) { + pub fn for_each_mut<'a>(&'a mut self, f: impl FnMut(>::Item)) { // SAFE: system runs without conflicts with other systems. same-system queries have runtime // borrow checks when they conflict unsafe { @@ -303,7 +303,7 @@ where /// This can only be called for read-only queries, see [`Self::par_for_each_mut`] for /// write-queries. #[inline] - pub fn par_for_each<'s>( + pub fn par_for_each( &'s self, task_pool: &TaskPool, batch_size: usize, @@ -327,11 +327,11 @@ where /// Runs `f` on each query result in parallel using the given task pool. #[inline] - pub fn par_for_each_mut<'s>( - &'s mut self, + pub fn par_for_each_mut<'a>( + &'a mut self, task_pool: &TaskPool, batch_size: usize, - f: impl Fn(>::Item) + Send + Sync + Clone, + f: impl Fn(>::Item) + Send + Sync + Clone, ) { // SAFE: system runs without conflicts with other systems. same-system queries have runtime // borrow checks when they conflict @@ -351,7 +351,10 @@ where /// /// This can only be called for read-only queries, see [`Self::get_mut`] for write-queries. #[inline] - pub fn get(&self, entity: Entity) -> Result<::Item, QueryEntityError> + pub fn get( + &'s self, + entity: Entity, + ) -> Result<>::Item, QueryEntityError> where Q::Fetch: ReadOnlyFetch, { @@ -406,7 +409,10 @@ where /// entity does not have the given component type or if the given component type does not match /// this query. #[inline] - pub fn get_component(&self, entity: Entity) -> Result<&T, QueryComponentError> { + pub fn get_component( + &self, + entity: Entity, + ) -> Result<&'w T, QueryComponentError> { let world = self.world; let entity_ref = world .get_entity(entity) @@ -511,7 +517,7 @@ where /// ``` /// /// This can only be called for read-only queries, see [`Self::single_mut`] for write-queries. - pub fn single(&self) -> Result<>::Item, QuerySingleError> + pub fn single(&'s self) -> Result<>::Item, QuerySingleError> where Q::Fetch: ReadOnlyFetch, { diff --git a/crates/bevy_ecs/src/system/system_param.rs b/crates/bevy_ecs/src/system/system_param.rs index 0499948755..2b496e9e63 100644 --- a/crates/bevy_ecs/src/system/system_param.rs +++ b/crates/bevy_ecs/src/system/system_param.rs @@ -27,11 +27,14 @@ use std::{ /// /// ``` /// # use bevy_ecs::prelude::*; +/// use std::marker::PhantomData; /// use bevy_ecs::system::SystemParam; /// /// #[derive(SystemParam)] -/// struct MyParam<'a> { -/// foo: Res<'a, usize>, +/// struct MyParam<'w, 's> { +/// foo: Res<'w, usize>, +/// #[system_param(ignore)] +/// marker: PhantomData<&'s usize>, /// } /// /// fn my_system(param: MyParam) { @@ -41,7 +44,7 @@ use std::{ /// # my_system.system(); /// ``` pub trait SystemParam: Sized { - type Fetch: for<'a> SystemParamFetch<'a>; + type Fetch: for<'w, 's> SystemParamFetch<'w, 's>; } /// The state of a [`SystemParam`]. @@ -80,21 +83,21 @@ pub unsafe trait SystemParamState: Send + Sync + 'static { /// This must only be implemented for [`SystemParamFetch`] impls that exclusively read the World passed in to [`SystemParamFetch::get_param`] pub unsafe trait ReadOnlySystemParamFetch {} -pub trait SystemParamFetch<'a>: SystemParamState { +pub trait SystemParamFetch<'world, 'state>: SystemParamState { type Item; /// # Safety /// /// This call might access any of the input parameters in an unsafe way. Make sure the data /// access is safe in the context of the system scheduler. unsafe fn get_param( - state: &'a mut Self, + state: &'state mut Self, system_meta: &SystemMeta, - world: &'a World, + world: &'world World, change_tick: u32, ) -> Self::Item; } -impl<'a, Q: WorldQuery + 'static, F: WorldQuery + 'static> SystemParam for Query<'a, Q, F> +impl<'w, 's, Q: WorldQuery + 'static, F: WorldQuery + 'static> SystemParam for Query<'w, 's, Q, F> where F::Fetch: FilterFetch, { @@ -146,17 +149,18 @@ where fn default_config() {} } -impl<'a, Q: WorldQuery + 'static, F: WorldQuery + 'static> SystemParamFetch<'a> for QueryState +impl<'w, 's, Q: WorldQuery + 'static, F: WorldQuery + 'static> SystemParamFetch<'w, 's> + for QueryState where F::Fetch: FilterFetch, { - type Item = Query<'a, Q, F>; + type Item = Query<'w, 's, Q, F>; #[inline] unsafe fn get_param( - state: &'a mut Self, + state: &'s mut Self, system_meta: &SystemMeta, - world: &'a World, + world: &'w World, change_tick: u32, ) -> Self::Item { Query::new(world, state, system_meta.last_change_tick, change_tick) @@ -184,7 +188,13 @@ fn assert_component_access_compatibility( query_type, filter_type, system_name, accesses); } -pub struct QuerySet(T); +pub struct QuerySet<'w, 's, T> { + query_states: &'s T, + world: &'w World, + last_change_tick: u32, + change_tick: u32, +} + pub struct QuerySetState(T); impl_query_set!(); @@ -228,6 +238,10 @@ impl<'w, T: Component> Res<'w, T> { self.ticks .is_changed(self.last_change_tick, self.change_tick) } + + pub fn into_inner(self) -> &'w T { + self.value + } } impl<'w, T: Component> Deref for Res<'w, T> { @@ -286,14 +300,14 @@ unsafe impl SystemParamState for ResState { fn default_config() {} } -impl<'a, T: Component> SystemParamFetch<'a> for ResState { - type Item = Res<'a, T>; +impl<'w, 's, T: Component> SystemParamFetch<'w, 's> for ResState { + type Item = Res<'w, T>; #[inline] unsafe fn get_param( - state: &'a mut Self, + state: &'s mut Self, system_meta: &SystemMeta, - world: &'a World, + world: &'w World, change_tick: u32, ) -> Self::Item { let column = world @@ -334,14 +348,14 @@ unsafe impl SystemParamState for OptionResState { fn default_config() {} } -impl<'a, T: Component> SystemParamFetch<'a> for OptionResState { - type Item = Option>; +impl<'w, 's, T: Component> SystemParamFetch<'w, 's> for OptionResState { + type Item = Option>; #[inline] unsafe fn get_param( - state: &'a mut Self, + state: &'s mut Self, system_meta: &SystemMeta, - world: &'a World, + world: &'w World, change_tick: u32, ) -> Self::Item { world @@ -400,14 +414,14 @@ unsafe impl SystemParamState for ResMutState { fn default_config() {} } -impl<'a, T: Component> SystemParamFetch<'a> for ResMutState { - type Item = ResMut<'a, T>; +impl<'w, 's, T: Component> SystemParamFetch<'w, 's> for ResMutState { + type Item = ResMut<'w, T>; #[inline] unsafe fn get_param( - state: &'a mut Self, + state: &'s mut Self, system_meta: &SystemMeta, - world: &'a World, + world: &'w World, change_tick: u32, ) -> Self::Item { let value = world @@ -447,14 +461,14 @@ unsafe impl SystemParamState for OptionResMutState { fn default_config() {} } -impl<'a, T: Component> SystemParamFetch<'a> for OptionResMutState { - type Item = Option>; +impl<'w, 's, T: Component> SystemParamFetch<'w, 's> for OptionResMutState { + type Item = Option>; #[inline] unsafe fn get_param( - state: &'a mut Self, + state: &'s mut Self, system_meta: &SystemMeta, - world: &'a World, + world: &'w World, change_tick: u32, ) -> Self::Item { world @@ -470,7 +484,7 @@ impl<'a, T: Component> SystemParamFetch<'a> for OptionResMutState { } } -impl<'a> SystemParam for Commands<'a> { +impl<'w, 's> SystemParam for Commands<'w, 's> { type Fetch = CommandQueue; } @@ -492,14 +506,14 @@ unsafe impl SystemParamState for CommandQueue { fn default_config() {} } -impl<'a> SystemParamFetch<'a> for CommandQueue { - type Item = Commands<'a>; +impl<'w, 's> SystemParamFetch<'w, 's> for CommandQueue { + type Item = Commands<'w, 's>; #[inline] unsafe fn get_param( - state: &'a mut Self, + state: &'s mut Self, _system_meta: &SystemMeta, - world: &'a World, + world: &'w World, _change_tick: u32, ) -> Self::Item { Commands::new(state, world) @@ -582,14 +596,14 @@ unsafe impl SystemParamState for LocalState { } } -impl<'a, T: Component + FromWorld> SystemParamFetch<'a> for LocalState { - type Item = Local<'a, T>; +impl<'w, 's, T: Component + FromWorld> SystemParamFetch<'w, 's> for LocalState { + type Item = Local<'s, T>; #[inline] unsafe fn get_param( - state: &'a mut Self, + state: &'s mut Self, _system_meta: &SystemMeta, - _world: &'a World, + _world: &'w World, _change_tick: u32, ) -> Self::Item { Local(&mut state.0) @@ -655,14 +669,14 @@ unsafe impl SystemParamState for RemovedComponentsState { fn default_config() {} } -impl<'a, T: Component> SystemParamFetch<'a> for RemovedComponentsState { - type Item = RemovedComponents<'a, T>; +impl<'w, 's, T: Component> SystemParamFetch<'w, 's> for RemovedComponentsState { + type Item = RemovedComponents<'w, T>; #[inline] unsafe fn get_param( - state: &'a mut Self, + state: &'s mut Self, _system_meta: &SystemMeta, - world: &'a World, + world: &'w World, _change_tick: u32, ) -> Self::Item { RemovedComponents { @@ -770,14 +784,14 @@ unsafe impl SystemParamState for NonSendState { fn default_config() {} } -impl<'a, T: 'static> SystemParamFetch<'a> for NonSendState { - type Item = NonSend<'a, T>; +impl<'w, 's, T: 'static> SystemParamFetch<'w, 's> for NonSendState { + type Item = NonSend<'w, T>; #[inline] unsafe fn get_param( - state: &'a mut Self, + state: &'s mut Self, system_meta: &SystemMeta, - world: &'a World, + world: &'w World, change_tick: u32, ) -> Self::Item { world.validate_non_send_access::(); @@ -803,7 +817,7 @@ impl<'a, T: 'static> SystemParamFetch<'a> for NonSendState { /// The [`SystemParamState`] of `Option>`. pub struct OptionNonSendState(NonSendState); -impl<'a, T: Component> SystemParam for Option> { +impl<'w, T: Component> SystemParam for Option> { type Fetch = OptionNonSendState; } @@ -820,14 +834,14 @@ unsafe impl SystemParamState for OptionNonSendState { fn default_config() {} } -impl<'a, T: 'static> SystemParamFetch<'a> for OptionNonSendState { - type Item = Option>; +impl<'w, 's, T: 'static> SystemParamFetch<'w, 's> for OptionNonSendState { + type Item = Option>; #[inline] unsafe fn get_param( - state: &'a mut Self, + state: &'s mut Self, system_meta: &SystemMeta, - world: &'a World, + world: &'w World, change_tick: u32, ) -> Self::Item { world.validate_non_send_access::(); @@ -889,14 +903,14 @@ unsafe impl SystemParamState for NonSendMutState { fn default_config() {} } -impl<'a, T: 'static> SystemParamFetch<'a> for NonSendMutState { - type Item = NonSendMut<'a, T>; +impl<'w, 's, T: 'static> SystemParamFetch<'w, 's> for NonSendMutState { + type Item = NonSendMut<'w, T>; #[inline] unsafe fn get_param( - state: &'a mut Self, + state: &'s mut Self, system_meta: &SystemMeta, - world: &'a World, + world: &'w World, change_tick: u32, ) -> Self::Item { world.validate_non_send_access::(); @@ -937,14 +951,14 @@ unsafe impl SystemParamState for OptionNonSendMutState { fn default_config() {} } -impl<'a, T: 'static> SystemParamFetch<'a> for OptionNonSendMutState { - type Item = Option>; +impl<'w, 's, T: 'static> SystemParamFetch<'w, 's> for OptionNonSendMutState { + type Item = Option>; #[inline] unsafe fn get_param( - state: &'a mut Self, + state: &'s mut Self, system_meta: &SystemMeta, - world: &'a World, + world: &'w World, change_tick: u32, ) -> Self::Item { world.validate_non_send_access::(); @@ -982,14 +996,14 @@ unsafe impl SystemParamState for ArchetypesState { fn default_config() {} } -impl<'a> SystemParamFetch<'a> for ArchetypesState { - type Item = &'a Archetypes; +impl<'w, 's> SystemParamFetch<'w, 's> for ArchetypesState { + type Item = &'w Archetypes; #[inline] unsafe fn get_param( - _state: &'a mut Self, + _state: &'s mut Self, _system_meta: &SystemMeta, - world: &'a World, + world: &'w World, _change_tick: u32, ) -> Self::Item { world.archetypes() @@ -1017,14 +1031,14 @@ unsafe impl SystemParamState for ComponentsState { fn default_config() {} } -impl<'a> SystemParamFetch<'a> for ComponentsState { - type Item = &'a Components; +impl<'w, 's> SystemParamFetch<'w, 's> for ComponentsState { + type Item = &'w Components; #[inline] unsafe fn get_param( - _state: &'a mut Self, + _state: &'s mut Self, _system_meta: &SystemMeta, - world: &'a World, + world: &'w World, _change_tick: u32, ) -> Self::Item { world.components() @@ -1052,14 +1066,14 @@ unsafe impl SystemParamState for EntitiesState { fn default_config() {} } -impl<'a> SystemParamFetch<'a> for EntitiesState { - type Item = &'a Entities; +impl<'w, 's> SystemParamFetch<'w, 's> for EntitiesState { + type Item = &'w Entities; #[inline] unsafe fn get_param( - _state: &'a mut Self, + _state: &'s mut Self, _system_meta: &SystemMeta, - world: &'a World, + world: &'w World, _change_tick: u32, ) -> Self::Item { world.entities() @@ -1087,14 +1101,14 @@ unsafe impl SystemParamState for BundlesState { fn default_config() {} } -impl<'a> SystemParamFetch<'a> for BundlesState { - type Item = &'a Bundles; +impl<'w, 's> SystemParamFetch<'w, 's> for BundlesState { + type Item = &'w Bundles; #[inline] unsafe fn get_param( - _state: &'a mut Self, + _state: &'s mut Self, _system_meta: &SystemMeta, - world: &'a World, + world: &'w World, _change_tick: u32, ) -> Self::Item { world.bundles() @@ -1127,13 +1141,13 @@ unsafe impl SystemParamState for SystemChangeTickState { fn default_config() {} } -impl<'a> SystemParamFetch<'a> for SystemChangeTickState { +impl<'w, 's> SystemParamFetch<'w, 's> for SystemChangeTickState { type Item = SystemChangeTick; unsafe fn get_param( - _state: &mut Self, + _state: &'s mut Self, system_meta: &SystemMeta, - _world: &World, + _world: &'w World, change_tick: u32, ) -> Self::Item { SystemChangeTick { @@ -1154,15 +1168,15 @@ macro_rules! impl_system_param_tuple { #[allow(unused_variables)] #[allow(non_snake_case)] - impl<'a, $($param: SystemParamFetch<'a>),*> SystemParamFetch<'a> for ($($param,)*) { + impl<'w, 's, $($param: SystemParamFetch<'w, 's>),*> SystemParamFetch<'w, 's> for ($($param,)*) { type Item = ($($param::Item,)*); #[inline] #[allow(clippy::unused_unit)] unsafe fn get_param( - state: &'a mut Self, + state: &'s mut Self, system_meta: &SystemMeta, - world: &'a World, + world: &'w World, change_tick: u32, ) -> Self::Item { diff --git a/crates/bevy_render/src/camera/camera.rs b/crates/bevy_render/src/camera/camera.rs index f3f63ca40a..1ac86b41a4 100644 --- a/crates/bevy_render/src/camera/camera.rs +++ b/crates/bevy_render/src/camera/camera.rs @@ -4,9 +4,10 @@ use bevy_ecs::{ component::Component, entity::Entity, event::EventReader, + prelude::QueryState, query::Added, reflect::ReflectComponent, - system::{Query, QuerySet, Res}, + system::{QuerySet, Res}, }; use bevy_math::{Mat4, Vec2, Vec3}; use bevy_reflect::{Reflect, ReflectDeserialize}; @@ -70,8 +71,8 @@ pub fn camera_system( mut window_created_events: EventReader, windows: Res, mut queries: QuerySet<( - Query<(Entity, &mut Camera, &mut T)>, - Query>, + QueryState<(Entity, &mut Camera, &mut T)>, + QueryState>, )>, ) { let mut changed_window_ids = Vec::new(); @@ -99,7 +100,7 @@ pub fn camera_system( for entity in &mut queries.q1().iter() { added_cameras.push(entity); } - for (entity, mut camera, mut camera_projection) in queries.q0_mut().iter_mut() { + for (entity, mut camera, mut camera_projection) in queries.q0().iter_mut() { if let Some(window) = windows.get(camera.window) { if changed_window_ids.contains(&window.id()) || added_cameras.contains(&entity) diff --git a/crates/bevy_render/src/draw.rs b/crates/bevy_render/src/draw.rs index 6faac65c32..9d4b6ce54f 100644 --- a/crates/bevy_render/src/draw.rs +++ b/crates/bevy_render/src/draw.rs @@ -14,7 +14,7 @@ use bevy_ecs::{ system::{Query, Res, ResMut, SystemParam}, }; use bevy_reflect::Reflect; -use std::{ops::Range, sync::Arc}; +use std::{marker::PhantomData, ops::Range, sync::Arc}; use thiserror::Error; /// A queued command for the renderer @@ -164,18 +164,20 @@ pub enum DrawError { } #[derive(SystemParam)] -pub struct DrawContext<'a> { - pub pipelines: ResMut<'a, Assets>, - pub shaders: ResMut<'a, Assets>, - pub asset_render_resource_bindings: ResMut<'a, AssetRenderResourceBindings>, - pub pipeline_compiler: ResMut<'a, PipelineCompiler>, - pub render_resource_context: Res<'a, Box>, - pub shared_buffers: ResMut<'a, SharedBuffers>, +pub struct DrawContext<'w, 's> { + pub pipelines: ResMut<'w, Assets>, + pub shaders: ResMut<'w, Assets>, + pub asset_render_resource_bindings: ResMut<'w, AssetRenderResourceBindings>, + pub pipeline_compiler: ResMut<'w, PipelineCompiler>, + pub render_resource_context: Res<'w, Box>, + pub shared_buffers: ResMut<'w, SharedBuffers>, #[system_param(ignore)] pub current_pipeline: Option>, + #[system_param(ignore)] + marker: PhantomData<&'s usize>, } -impl<'a> DrawContext<'a> { +impl<'w, 's> DrawContext<'w, 's> { pub fn get_uniform_buffer( &mut self, render_resource: &T, diff --git a/crates/bevy_render/src/mesh/mesh.rs b/crates/bevy_render/src/mesh/mesh.rs index 29d2cdf19d..b8d42eb060 100644 --- a/crates/bevy_render/src/mesh/mesh.rs +++ b/crates/bevy_render/src/mesh/mesh.rs @@ -9,8 +9,9 @@ use bevy_core::cast_slice; use bevy_ecs::{ entity::Entity, event::EventReader, + prelude::QueryState, query::{Changed, With}, - system::{Local, Query, QuerySet, Res}, + system::{Local, QuerySet, Res}, world::Mut, }; use bevy_math::*; @@ -512,8 +513,8 @@ pub fn mesh_resource_provider_system( meshes: Res>, mut mesh_events: EventReader>, mut queries: QuerySet<( - Query<&mut RenderPipelines, With>>, - Query<(Entity, &Handle, &mut RenderPipelines), Changed>>, + QueryState<&mut RenderPipelines, With>>, + QueryState<(Entity, &Handle, &mut RenderPipelines), Changed>>, )>, ) { let mut changed_meshes = HashSet::default(); @@ -573,7 +574,7 @@ pub fn mesh_resource_provider_system( if let Some(mesh_entities) = state.mesh_entities.get_mut(changed_mesh_handle) { for entity in mesh_entities.entities.iter() { - if let Ok(render_pipelines) = queries.q0_mut().get_mut(*entity) { + if let Ok(render_pipelines) = queries.q0().get_mut(*entity) { update_entity_mesh( render_resource_context, mesh, @@ -587,7 +588,7 @@ pub fn mesh_resource_provider_system( } // handover buffers to pipeline - for (entity, handle, render_pipelines) in queries.q1_mut().iter_mut() { + for (entity, handle, render_pipelines) in queries.q1().iter_mut() { let mesh_entities = state .mesh_entities .entry(handle.clone_weak()) diff --git a/crates/bevy_render/src/render_graph/nodes/render_resources_node.rs b/crates/bevy_render/src/render_graph/nodes/render_resources_node.rs index e0a6624637..453ffa6faa 100644 --- a/crates/bevy_render/src/render_graph/nodes/render_resources_node.rs +++ b/crates/bevy_render/src/render_graph/nodes/render_resources_node.rs @@ -13,10 +13,9 @@ use bevy_app::EventReader; use bevy_asset::{Asset, AssetEvent, Assets, Handle, HandleId}; use bevy_ecs::{ entity::Entity, + prelude::QueryState, query::{Changed, Or, With}, - system::{ - BoxedSystem, ConfigurableSystem, Local, Query, QuerySet, RemovedComponents, Res, ResMut, - }, + system::{BoxedSystem, ConfigurableSystem, Local, QuerySet, RemovedComponents, Res, ResMut}, world::World, }; use bevy_utils::HashMap; @@ -437,8 +436,11 @@ fn render_resources_node_system( render_resource_context: Res>, removed: RemovedComponents, mut queries: QuerySet<( - Query<(Entity, &T, &Visible, &mut RenderPipelines), Or<(Changed, Changed)>>, - Query<(Entity, &T, &Visible, &mut RenderPipelines)>, + QueryState< + (Entity, &T, &Visible, &mut RenderPipelines), + Or<(Changed, Changed)>, + >, + QueryState<(Entity, &T, &Visible, &mut RenderPipelines)>, )>, ) { let state = state.deref_mut(); @@ -446,7 +448,7 @@ fn render_resources_node_system( let render_resource_context = &**render_resource_context; uniform_buffer_arrays.begin_update(); // initialize uniform buffer arrays using the first RenderResources - if let Some((_, first, _, _)) = queries.q0_mut().iter_mut().next() { + if let Some((_, first, _, _)) = queries.q0().iter_mut().next() { uniform_buffer_arrays.initialize(first, render_resource_context); } @@ -456,8 +458,7 @@ fn render_resources_node_system( // handle entities that were waiting for texture loads on the last update for entity in std::mem::take(&mut *entities_waiting_for_textures) { - if let Ok((entity, uniforms, _visible, mut render_pipelines)) = - queries.q1_mut().get_mut(entity) + if let Ok((entity, uniforms, _visible, mut render_pipelines)) = queries.q1().get_mut(entity) { if !setup_uniform_texture_resources::( uniforms, @@ -469,7 +470,7 @@ fn render_resources_node_system( } } - for (entity, uniforms, visible, mut render_pipelines) in queries.q0_mut().iter_mut() { + for (entity, uniforms, visible, mut render_pipelines) in queries.q0().iter_mut() { if !visible.is_visible { continue; } @@ -498,8 +499,7 @@ fn render_resources_node_system( // if the buffer array was resized, write all entities to the new buffer, otherwise // only write changes if resized { - for (entity, uniforms, visible, mut render_pipelines) in - queries.q1_mut().iter_mut() + for (entity, uniforms, visible, mut render_pipelines) in queries.q1().iter_mut() { if !visible.is_visible { continue; @@ -515,8 +515,7 @@ fn render_resources_node_system( ); } } else { - for (entity, uniforms, visible, mut render_pipelines) in - queries.q0_mut().iter_mut() + for (entity, uniforms, visible, mut render_pipelines) in queries.q0().iter_mut() { if !visible.is_visible { continue; @@ -621,8 +620,8 @@ fn asset_render_resources_node_system( render_resource_context: Res>, removed_handles: RemovedComponents>, mut queries: QuerySet<( - Query<(&Handle, &mut RenderPipelines), Changed>>, - Query<&mut RenderPipelines, With>>, + QueryState<(&Handle, &mut RenderPipelines), Changed>>, + QueryState<&mut RenderPipelines, With>>, )>, ) { let state = state.deref_mut(); @@ -752,7 +751,7 @@ fn asset_render_resources_node_system( // update removed entity asset mapping for entity in removed_handles.iter() { - if let Ok(mut render_pipelines) = queries.q1_mut().get_mut(entity) { + if let Ok(mut render_pipelines) = queries.q1().get_mut(entity) { render_pipelines .bindings .remove_asset_with_type(TypeId::of::()) @@ -760,7 +759,7 @@ fn asset_render_resources_node_system( } // update changed entity asset mapping - for (asset_handle, mut render_pipelines) in queries.q0_mut().iter_mut() { + for (asset_handle, mut render_pipelines) in queries.q0().iter_mut() { render_pipelines .bindings .remove_asset_with_type(TypeId::of::()); diff --git a/crates/bevy_render/src/wireframe/mod.rs b/crates/bevy_render/src/wireframe/mod.rs index d98eb165ab..fc95816323 100644 --- a/crates/bevy_render/src/wireframe/mod.rs +++ b/crates/bevy_render/src/wireframe/mod.rs @@ -8,9 +8,9 @@ use crate::{ use bevy_app::prelude::*; use bevy_asset::{Assets, Handle, HandleUntyped}; use bevy_ecs::{ - query::With, + query::{QueryState, With}, reflect::ReflectComponent, - system::{Query, QuerySet, Res}, + system::{QuerySet, Res}, world::Mut, }; use bevy_reflect::{Reflect, TypeUuid}; @@ -62,8 +62,8 @@ pub fn draw_wireframes_system( meshes: Res>, wireframe_config: Res, mut query: QuerySet<( - Query<(&mut Draw, &mut RenderPipelines, &Handle, &Visible)>, - Query<(&mut Draw, &mut RenderPipelines, &Handle, &Visible), With>, + QueryState<(&mut Draw, &mut RenderPipelines, &Handle, &Visible)>, + QueryState<(&mut Draw, &mut RenderPipelines, &Handle, &Visible), With>, )>, ) { let iterator = |(mut draw, mut render_pipelines, mesh_handle, visible): ( @@ -123,8 +123,8 @@ pub fn draw_wireframes_system( }; if wireframe_config.global { - query.q0_mut().iter_mut().for_each(iterator); + query.q0().iter_mut().for_each(iterator); } else { - query.q1_mut().iter_mut().for_each(iterator); + query.q1().iter_mut().for_each(iterator); } } diff --git a/crates/bevy_scene/src/command.rs b/crates/bevy_scene/src/command.rs index 42554e9179..aef43a2e7f 100644 --- a/crates/bevy_scene/src/command.rs +++ b/crates/bevy_scene/src/command.rs @@ -23,7 +23,7 @@ pub trait SpawnSceneCommands { fn spawn_scene(&mut self, scene: Handle); } -impl<'a> SpawnSceneCommands for Commands<'a> { +impl<'w, 's> SpawnSceneCommands for Commands<'w, 's> { fn spawn_scene(&mut self, scene_handle: Handle) { self.add(SpawnScene { scene_handle }); } @@ -45,7 +45,7 @@ pub trait SpawnSceneAsChildCommands { fn spawn_scene(&mut self, scene: Handle) -> &mut Self; } -impl<'a, 'b> SpawnSceneAsChildCommands for ChildBuilder<'a, 'b> { +impl<'w, 's, 'a> SpawnSceneAsChildCommands for ChildBuilder<'w, 's, 'a> { fn spawn_scene(&mut self, scene_handle: Handle) -> &mut Self { self.add_command(SpawnSceneAsChild { scene_handle, diff --git a/crates/bevy_text/src/text2d.rs b/crates/bevy_text/src/text2d.rs index 890f57bbf1..88dc89575c 100644 --- a/crates/bevy_text/src/text2d.rs +++ b/crates/bevy_text/src/text2d.rs @@ -2,7 +2,7 @@ use bevy_asset::Assets; use bevy_ecs::{ bundle::Bundle, entity::Entity, - query::{Changed, With, Without}, + query::{Changed, QueryState, With, Without}, system::{Local, Query, QuerySet, Res, ResMut}, }; use bevy_math::{Size, Vec3}; @@ -136,12 +136,12 @@ pub fn text2d_system( mut font_atlas_set_storage: ResMut>, mut text_pipeline: ResMut, mut text_queries: QuerySet<( - Query, Changed)>, - Query<(&Text, &mut Text2dSize), With>, + QueryState, Changed)>, + QueryState<(&Text, &mut Text2dSize), With>, )>, ) { // Adds all entities where the text or the style has changed to the local queue - for entity in text_queries.q0_mut().iter_mut() { + for entity in text_queries.q0().iter_mut() { queued_text.entities.push(entity); } @@ -157,7 +157,7 @@ pub fn text2d_system( // Computes all text in the local queue let mut new_queue = Vec::new(); - let query = text_queries.q1_mut(); + let mut query = text_queries.q1(); for entity in queued_text.entities.drain(..) { if let Ok((text, mut calculated_size)) = query.get_mut(entity) { match text_pipeline.queue_text( diff --git a/crates/bevy_transform/src/hierarchy/child_builder.rs b/crates/bevy_transform/src/hierarchy/child_builder.rs index 71fc54aeb2..3e625f4e85 100644 --- a/crates/bevy_transform/src/hierarchy/child_builder.rs +++ b/crates/bevy_transform/src/hierarchy/child_builder.rs @@ -40,8 +40,8 @@ pub struct PushChildren { children: SmallVec<[Entity; 8]>, } -pub struct ChildBuilder<'a, 'b> { - commands: &'b mut Commands<'a>, +pub struct ChildBuilder<'w, 's, 'a> { + commands: &'a mut Commands<'w, 's>, push_children: PushChildren, } @@ -71,14 +71,14 @@ impl Command for PushChildren { } } -impl<'a, 'b> ChildBuilder<'a, 'b> { - pub fn spawn_bundle(&mut self, bundle: impl Bundle) -> EntityCommands<'a, '_> { +impl<'w, 's, 'a> ChildBuilder<'w, 's, 'a> { + pub fn spawn_bundle(&mut self, bundle: impl Bundle) -> EntityCommands<'w, 's, '_> { let e = self.commands.spawn_bundle(bundle); self.push_children.children.push(e.id()); e } - pub fn spawn(&mut self) -> EntityCommands<'a, '_> { + pub fn spawn(&mut self) -> EntityCommands<'w, 's, '_> { let e = self.commands.spawn(); self.push_children.children.push(e.id()); e @@ -100,7 +100,7 @@ pub trait BuildChildren { fn insert_children(&mut self, index: usize, children: &[Entity]) -> &mut Self; } -impl<'a, 'b> BuildChildren for EntityCommands<'a, 'b> { +impl<'w, 's, 'a> BuildChildren for EntityCommands<'w, 's, 'a> { fn with_children(&mut self, spawn_children: impl FnOnce(&mut ChildBuilder)) -> &mut Self { let parent = self.id(); let push_children = { diff --git a/crates/bevy_transform/src/hierarchy/hierarchy.rs b/crates/bevy_transform/src/hierarchy/hierarchy.rs index d50f241e43..b8e1bf4532 100644 --- a/crates/bevy_transform/src/hierarchy/hierarchy.rs +++ b/crates/bevy_transform/src/hierarchy/hierarchy.rs @@ -47,7 +47,7 @@ pub trait DespawnRecursiveExt { fn despawn_recursive(&mut self); } -impl<'a, 'b> DespawnRecursiveExt for EntityCommands<'a, 'b> { +impl<'w, 's, 'a> DespawnRecursiveExt for EntityCommands<'w, 's, 'a> { /// Despawns the provided entity and its children. fn despawn_recursive(&mut self) { let entity = self.id(); diff --git a/crates/bevy_ui/src/widget/text.rs b/crates/bevy_ui/src/widget/text.rs index 3e5c91c9ea..c59230b4b3 100644 --- a/crates/bevy_ui/src/widget/text.rs +++ b/crates/bevy_ui/src/widget/text.rs @@ -2,7 +2,7 @@ use crate::{CalculatedSize, Node, Style, Val}; use bevy_asset::Assets; use bevy_ecs::{ entity::Entity, - query::{Changed, Or, With, Without}, + query::{Changed, Or, QueryState, With, Without}, system::{Local, Query, QuerySet, Res, ResMut}, }; use bevy_math::Size; @@ -53,9 +53,9 @@ pub fn text_system( mut font_atlas_set_storage: ResMut>, mut text_pipeline: ResMut, mut text_queries: QuerySet<( - Query, Changed