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:
115b170d1f/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<Q, F = ()>` parameter to enable these read-only scenarios, but I'd rather not add another type to the type zoo.
This commit is contained in:
Carter Anderson 2021-08-15 20:51:53 +00:00
parent a89a954a17
commit 9d453530fa
20 changed files with 481 additions and 256 deletions

View File

@ -9,8 +9,8 @@ use syn::{
parse_macro_input, parse_macro_input,
punctuated::Punctuated, punctuated::Punctuated,
token::Comma, token::Comma,
Data, DataStruct, DeriveInput, Field, Fields, GenericParam, Ident, Index, Lifetime, LitInt, Data, DataStruct, DeriveInput, Field, Fields, GenericParam, Ident, Index, LitInt, Path, Result,
Path, Result, Token, Token,
}; };
struct AllTuples { struct AllTuples {
@ -176,36 +176,26 @@ fn get_idents(fmt_string: fn(usize) -> String, count: usize) -> Vec<Ident> {
.collect::<Vec<Ident>>() .collect::<Vec<Ident>>()
} }
fn get_lifetimes(fmt_string: fn(usize) -> String, count: usize) -> Vec<Lifetime> {
(0..count)
.map(|i| Lifetime::new(&fmt_string(i), Span::call_site()))
.collect::<Vec<Lifetime>>()
}
#[proc_macro] #[proc_macro]
pub fn impl_query_set(_input: TokenStream) -> TokenStream { pub fn impl_query_set(_input: TokenStream) -> TokenStream {
let mut tokens = TokenStream::new(); let mut tokens = TokenStream::new();
let max_queries = 4; let max_queries = 4;
let queries = get_idents(|i| format!("Q{}", i), max_queries); let queries = get_idents(|i| format!("Q{}", i), max_queries);
let filters = get_idents(|i| format!("F{}", 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(); let mut query_fn_muts = Vec::new();
for i in 0..max_queries { for i in 0..max_queries {
let query = &queries[i]; let query = &queries[i];
let filter = &filters[i]; let filter = &filters[i];
let lifetime = &lifetimes[i];
let fn_name = Ident::new(&format!("q{}", i), Span::call_site()); 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); 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! { query_fn_muts.push(quote! {
pub fn #fn_name_mut(&mut self) -> &mut Query<#lifetime, #query, #filter> { pub fn #fn_name(&mut self) -> Query<'_, '_, #query, #filter> {
&mut self.0.#index // 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 { for query_count in 1..=max_queries {
let query = &queries[0..query_count]; let query = &queries[0..query_count];
let filter = &filters[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]; let query_fn_mut = &query_fn_muts[0..query_count];
tokens.extend(TokenStream::from(quote! { 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,)* where #(#filter::Fetch: FilterFetch,)*
{ {
type Fetch = QuerySetState<(#(QueryState<#query, #filter>,)*)>; type Fetch = QuerySetState<(#(QueryState<#query, #filter>,)*)>;
@ -270,27 +258,30 @@ pub fn impl_query_set(_input: TokenStream) -> TokenStream {
fn default_config() {} 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,)* where #(#filter::Fetch: FilterFetch,)*
{ {
type Item = QuerySet<(#(Query<'a, #query, #filter>,)*)>; type Item = QuerySet<'w, 's, (#(QueryState<#query, #filter>,)*)>;
#[inline] #[inline]
unsafe fn get_param( unsafe fn get_param(
state: &'a mut Self, state: &'s mut Self,
system_meta: &SystemMeta, system_meta: &SystemMeta,
world: &'a World, world: &'w World,
change_tick: u32, change_tick: u32,
) -> Self::Item { ) -> Self::Item {
let (#(#query,)*) = &state.0; QuerySet {
QuerySet((#(Query::new(world, #query, system_meta.last_change_tick, change_tick),)*)) 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,)* where #(#filter::Fetch: FilterFetch,)*
{ {
#(#query_fn)*
#(#query_fn_mut)* #(#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; type Item = #struct_name#ty_generics;
unsafe fn get_param( unsafe fn get_param(
state: &'a mut Self, state: &'s mut Self,
system_meta: &#path::system::SystemMeta, system_meta: &#path::system::SystemMeta,
world: &'a #path::world::World, world: &'w #path::world::World,
change_tick: u32, change_tick: u32,
) -> Self::Item { ) -> Self::Item {
#struct_name { #struct_name {

View File

@ -151,18 +151,20 @@ fn map_instance_event<T>(event_instance: &EventInstance<T>) -> &T {
/// Reads events of type `T` in order and tracks which events have already been read. /// Reads events of type `T` in order and tracks which events have already been read.
#[derive(SystemParam)] #[derive(SystemParam)]
pub struct EventReader<'a, T: Component> { pub struct EventReader<'w, 's, T: Component> {
last_event_count: Local<'a, (usize, PhantomData<T>)>, last_event_count: Local<'s, (usize, PhantomData<T>)>,
events: Res<'a, Events<T>>, events: Res<'w, Events<T>>,
} }
/// Sends events of type `T`. /// Sends events of type `T`.
#[derive(SystemParam)] #[derive(SystemParam)]
pub struct EventWriter<'a, T: Component> { pub struct EventWriter<'w, 's, T: Component> {
events: ResMut<'a, Events<T>>, events: ResMut<'w, Events<T>>,
#[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) { pub fn send(&mut self, event: T) {
self.events.send(event); 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 /// 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 /// event counter, which means subsequent event reads will not include events that happened
/// before now. /// before now.

View File

@ -117,11 +117,11 @@ where
} }
#[inline] #[inline]
pub fn get<'w>( pub fn get<'w, 's>(
&mut self, &'s mut self,
world: &'w World, world: &'w World,
entity: Entity, entity: Entity,
) -> Result<<Q::Fetch as Fetch<'w, '_>>::Item, QueryEntityError> ) -> Result<<Q::Fetch as Fetch<'w, 's>>::Item, QueryEntityError>
where where
Q::Fetch: ReadOnlyFetch, Q::Fetch: ReadOnlyFetch,
{ {
@ -130,11 +130,11 @@ where
} }
#[inline] #[inline]
pub fn get_mut<'w>( pub fn get_mut<'w, 's>(
&mut self, &'s mut self,
world: &'w mut World, world: &'w mut World,
entity: Entity, entity: Entity,
) -> Result<<Q::Fetch as Fetch<'w, '_>>::Item, QueryEntityError> { ) -> Result<<Q::Fetch as Fetch<'w, 's>>::Item, QueryEntityError> {
// SAFETY: query has unique world access // SAFETY: query has unique world access
unsafe { self.get_unchecked(world, entity) } 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 /// This does not check for mutable query correctness. To be safe, make sure mutable queries
/// have unique access to the components they query. /// have unique access to the components they query.
#[inline] #[inline]
pub unsafe fn get_unchecked<'w>( pub unsafe fn get_unchecked<'w, 's>(
&mut self, &'s mut self,
world: &'w World, world: &'w World,
entity: Entity, entity: Entity,
) -> Result<<Q::Fetch as Fetch<'w, '_>>::Item, QueryEntityError> { ) -> Result<<Q::Fetch as Fetch<'w, 's>>::Item, QueryEntityError> {
self.validate_world_and_update_archetypes(world); self.validate_world_and_update_archetypes(world);
self.get_unchecked_manual( self.get_unchecked_manual(
world, world,
@ -161,13 +161,13 @@ where
/// # Safety /// # Safety
/// This does not check for mutable query correctness. To be safe, make sure mutable queries /// This does not check for mutable query correctness. To be safe, make sure mutable queries
/// have unique access to the components they query. /// have unique access to the components they query.
pub unsafe fn get_unchecked_manual<'w>( pub unsafe fn get_unchecked_manual<'w, 's>(
&self, &'s self,
world: &'w World, world: &'w World,
entity: Entity, entity: Entity,
last_change_tick: u32, last_change_tick: u32,
change_tick: u32, change_tick: u32,
) -> Result<<Q::Fetch as Fetch<'w, '_>>::Item, QueryEntityError> { ) -> Result<<Q::Fetch as Fetch<'w, 's>>::Item, QueryEntityError> {
let location = world let location = world
.entities .entities
.get(entity) .get(entity)

View File

@ -16,14 +16,14 @@ pub trait Command: Send + Sync + 'static {
} }
/// A list of commands that will be run to modify a [`World`]. /// A list of commands that will be run to modify a [`World`].
pub struct Commands<'a> { pub struct Commands<'w, 's> {
queue: &'a mut CommandQueue, queue: &'s mut CommandQueue,
entities: &'a Entities, entities: &'w Entities,
} }
impl<'a> Commands<'a> { impl<'w, 's> Commands<'w, 's> {
/// Create a new `Commands` from a queue and a world. /// 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 { Self {
queue, queue,
entities: world.entities(), entities: world.entities(),
@ -50,7 +50,7 @@ impl<'a> Commands<'a> {
/// } /// }
/// # example_system.system(); /// # 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(); let entity = self.entities.reserve_entity();
EntityCommands { EntityCommands {
entity, entity,
@ -98,7 +98,7 @@ impl<'a> Commands<'a> {
/// } /// }
/// # example_system.system(); /// # 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(); let mut e = self.spawn();
e.insert_bundle(bundle); e.insert_bundle(bundle);
e e
@ -123,7 +123,7 @@ impl<'a> Commands<'a> {
/// } /// }
/// # example_system.system(); /// # 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 { EntityCommands {
entity, entity,
commands: self, commands: self,
@ -159,12 +159,12 @@ impl<'a> Commands<'a> {
} }
/// A list of commands that will be run to modify an [`Entity`]. /// 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, 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. /// Retrieves the current entity's unique [`Entity`] id.
#[inline] #[inline]
pub fn id(&self) -> Entity { pub fn id(&self) -> Entity {
@ -252,7 +252,7 @@ impl<'a, 'b> EntityCommands<'a, 'b> {
} }
/// Returns the underlying `[Commands]`. /// Returns the underlying `[Commands]`.
pub fn commands(&mut self) -> &mut Commands<'a> { pub fn commands(&mut self) -> &mut Commands<'w, 's> {
self.commands self.commands
} }
} }

View File

@ -87,7 +87,10 @@ impl<Param: SystemParam> SystemState<Param> {
/// Retrieve the [`SystemParam`] values. This can only be called when all parameters are read-only. /// Retrieve the [`SystemParam`] values. This can only be called when all parameters are read-only.
#[inline] #[inline]
pub fn get<'a>(&'a mut self, world: &'a World) -> <Param::Fetch as SystemParamFetch<'a>>::Item pub fn get<'w, 's>(
&'s mut self,
world: &'w World,
) -> <Param::Fetch as SystemParamFetch<'w, 's>>::Item
where where
Param::Fetch: ReadOnlySystemParamFetch, Param::Fetch: ReadOnlySystemParamFetch,
{ {
@ -98,10 +101,10 @@ impl<Param: SystemParam> SystemState<Param> {
/// Retrieve the mutable [`SystemParam`] values. /// Retrieve the mutable [`SystemParam`] values.
#[inline] #[inline]
pub fn get_mut<'a>( pub fn get_mut<'w, 's>(
&'a mut self, &'s mut self,
world: &'a mut World, world: &'w mut World,
) -> <Param::Fetch as SystemParamFetch<'a>>::Item { ) -> <Param::Fetch as SystemParamFetch<'w, 's>>::Item {
self.validate_world_and_update_archetypes(world); self.validate_world_and_update_archetypes(world);
// SAFE: World is uniquely borrowed and matches the World this SystemState was created with. // SAFE: World is uniquely borrowed and matches the World this SystemState was created with.
unsafe { self.get_unchecked_manual(world) } unsafe { self.get_unchecked_manual(world) }
@ -142,10 +145,10 @@ impl<Param: SystemParam> SystemState<Param> {
/// access is safe in the context of global [`World`] access. The passed-in [`World`] _must_ be the [`World`] the [`SystemState`] was /// access is safe in the context of global [`World`] access. The passed-in [`World`] _must_ be the [`World`] the [`SystemState`] was
/// created with. /// created with.
#[inline] #[inline]
pub unsafe fn get_unchecked_manual<'a>( pub unsafe fn get_unchecked_manual<'w, 's>(
&'a mut self, &'s mut self,
world: &'a World, world: &'w World,
) -> <Param::Fetch as SystemParamFetch<'a>>::Item { ) -> <Param::Fetch as SystemParamFetch<'w, 's>>::Item {
let change_tick = world.increment_change_tick(); let change_tick = world.increment_change_tick();
let param = <Param::Fetch as SystemParamFetch>::get_param( let param = <Param::Fetch as SystemParamFetch>::get_param(
&mut self.param_state, &mut self.param_state,

View File

@ -24,7 +24,7 @@ mod tests {
bundle::Bundles, bundle::Bundles,
component::Components, component::Components,
entity::{Entities, Entity}, entity::{Entities, Entity},
query::{Added, Changed, Or, With, Without}, query::{Added, Changed, Or, QueryState, With, Without},
schedule::{Schedule, Stage, SystemStage}, schedule::{Schedule, Stage, SystemStage},
system::{ system::{
ConfigurableSystem, IntoExclusiveSystem, IntoSystem, Local, Query, QuerySet, ConfigurableSystem, IntoExclusiveSystem, IntoSystem, Local, Query, QuerySet,
@ -131,9 +131,9 @@ mod tests {
// Regression test for issue #762 // Regression test for issue #762
fn query_system( fn query_system(
mut ran: ResMut<bool>, mut ran: ResMut<bool>,
set: QuerySet<( mut set: QuerySet<(
Query<(), Or<(Changed<A>, Changed<B>)>>, QueryState<(), Or<(Changed<A>, Changed<B>)>>,
Query<(), Or<(Added<A>, Added<B>)>>, QueryState<(), Or<(Added<A>, Added<B>)>>,
)>, )>,
) { ) {
let changed = set.q0().iter().count(); let changed = set.q0().iter().count();
@ -236,7 +236,7 @@ mod tests {
#[test] #[test]
fn query_set_system() { 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(); let mut world = World::default();
run_system(&mut world, sys); run_system(&mut world, sys);
} }
@ -244,7 +244,7 @@ mod tests {
#[test] #[test]
#[should_panic] #[should_panic]
fn conflicting_query_with_query_set_system() { 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(); let mut world = World::default();
run_system(&mut world, sys); run_system(&mut world, sys);
@ -253,7 +253,11 @@ mod tests {
#[test] #[test]
#[should_panic] #[should_panic]
fn conflicting_query_sets_system() { 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(); let mut world = World::default();
run_system(&mut world, sys); run_system(&mut world, sys);
@ -520,8 +524,11 @@ mod tests {
world.insert_resource(A(42)); world.insert_resource(A(42));
world.spawn().insert(B(7)); world.spawn().insert(B(7));
let mut system_state: SystemState<(Res<A>, Query<&B>, QuerySet<(Query<&C>, Query<&D>)>)> = let mut system_state: SystemState<(
SystemState::new(&mut world); Res<A>,
Query<&B>,
QuerySet<(QueryState<&C>, QueryState<&D>)>,
)> = SystemState::new(&mut world);
let (a, query, _) = system_state.get(&world); let (a, query, _) = system_state.get(&world);
assert_eq!(*a, A(42), "returned resource matches initial value"); assert_eq!(*a, A(42), "returned resource matches initial value");
assert_eq!( 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<Res<'static, A>>,
state_q: SystemState<Query<'static, 'static, &'static A>>,
}
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<Holder<'w>> {
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<Entity>) {
/// 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<Entity>) {
/// 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<Entity>) {
/// 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<Entity>) {
/// 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<Entity>) {
/// 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<Entity>) {
/// 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<Query<'static, 'static, &'static A>>,
/// state_w: SystemState<Query<'static, 'static, &'static mut A>>,
/// }
///
/// 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<Query<'static, 'static, &'static A>>,
/// state_w: SystemState<Query<'static, 'static, &'static mut A>>,
/// }
///
/// 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() {}

View File

@ -107,17 +107,17 @@ use thiserror::Error;
/// ///
/// This touches all the basics of queries, make sure to check out all the [`WorldQueries`](WorldQuery) /// This touches all the basics of queries, make sure to check out all the [`WorldQueries`](WorldQuery)
/// bevy has to offer. /// bevy has to offer.
pub struct Query<'w, Q: WorldQuery, F: WorldQuery = ()> pub struct Query<'world, 'state, Q: WorldQuery, F: WorldQuery = ()>
where where
F::Fetch: FilterFetch, F::Fetch: FilterFetch,
{ {
pub(crate) world: &'w World, pub(crate) world: &'world World,
pub(crate) state: &'w QueryState<Q, F>, pub(crate) state: &'state QueryState<Q, F>,
pub(crate) last_change_tick: u32, pub(crate) last_change_tick: u32,
pub(crate) 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 where
F::Fetch: FilterFetch, F::Fetch: FilterFetch,
{ {
@ -130,7 +130,7 @@ where
#[inline] #[inline]
pub(crate) unsafe fn new( pub(crate) unsafe fn new(
world: &'w World, world: &'w World,
state: &'w QueryState<Q, F>, state: &'s QueryState<Q, F>,
last_change_tick: u32, last_change_tick: u32,
change_tick: u32, change_tick: u32,
) -> Self { ) -> Self {
@ -146,7 +146,7 @@ where
/// ///
/// This can only be called for read-only queries, see [`Self::iter_mut`] for write-queries. /// This can only be called for read-only queries, see [`Self::iter_mut`] for write-queries.
#[inline] #[inline]
pub fn iter(&self) -> QueryIter<'_, '_, Q, F> pub fn iter(&'s self) -> QueryIter<'w, 's, Q, F>
where where
Q::Fetch: ReadOnlyFetch, 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. /// Returns an [`Iterator`] over all possible combinations of `K` query results without repetition.
/// This can only be called for read-only queries /// 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. /// 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. /// 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. /// This can only be called for read-only queries, see [`Self::for_each_mut`] for write-queries.
#[inline] #[inline]
pub fn for_each<'s>(&'s self, f: impl FnMut(<Q::Fetch as Fetch<'w, 's>>::Item)) pub fn for_each(&'s self, f: impl FnMut(<Q::Fetch as Fetch<'w, 's>>::Item))
where where
Q::Fetch: ReadOnlyFetch, Q::Fetch: ReadOnlyFetch,
{ {
@ -285,7 +285,7 @@ where
/// Runs `f` on each query result. This is faster than the equivalent iter() method, but cannot /// Runs `f` on each query result. This is faster than the equivalent iter() method, but cannot
/// be chained like a normal [`Iterator`]. /// be chained like a normal [`Iterator`].
#[inline] #[inline]
pub fn for_each_mut<'s>(&'s mut self, f: impl FnMut(<Q::Fetch as Fetch<'w, 's>>::Item)) { pub fn for_each_mut<'a>(&'a mut self, f: impl FnMut(<Q::Fetch as Fetch<'a, 'a>>::Item)) {
// SAFE: system runs without conflicts with other systems. same-system queries have runtime // SAFE: system runs without conflicts with other systems. same-system queries have runtime
// borrow checks when they conflict // borrow checks when they conflict
unsafe { unsafe {
@ -303,7 +303,7 @@ where
/// This can only be called for read-only queries, see [`Self::par_for_each_mut`] for /// This can only be called for read-only queries, see [`Self::par_for_each_mut`] for
/// write-queries. /// write-queries.
#[inline] #[inline]
pub fn par_for_each<'s>( pub fn par_for_each(
&'s self, &'s self,
task_pool: &TaskPool, task_pool: &TaskPool,
batch_size: usize, batch_size: usize,
@ -327,11 +327,11 @@ where
/// Runs `f` on each query result in parallel using the given task pool. /// Runs `f` on each query result in parallel using the given task pool.
#[inline] #[inline]
pub fn par_for_each_mut<'s>( pub fn par_for_each_mut<'a>(
&'s mut self, &'a mut self,
task_pool: &TaskPool, task_pool: &TaskPool,
batch_size: usize, batch_size: usize,
f: impl Fn(<Q::Fetch as Fetch<'w, 's>>::Item) + Send + Sync + Clone, f: impl Fn(<Q::Fetch as Fetch<'a, 'a>>::Item) + Send + Sync + Clone,
) { ) {
// SAFE: system runs without conflicts with other systems. same-system queries have runtime // SAFE: system runs without conflicts with other systems. same-system queries have runtime
// borrow checks when they conflict // 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. /// This can only be called for read-only queries, see [`Self::get_mut`] for write-queries.
#[inline] #[inline]
pub fn get(&self, entity: Entity) -> Result<<Q::Fetch as Fetch>::Item, QueryEntityError> pub fn get(
&'s self,
entity: Entity,
) -> Result<<Q::Fetch as Fetch<'w, 's>>::Item, QueryEntityError>
where where
Q::Fetch: ReadOnlyFetch, 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 /// entity does not have the given component type or if the given component type does not match
/// this query. /// this query.
#[inline] #[inline]
pub fn get_component<T: Component>(&self, entity: Entity) -> Result<&T, QueryComponentError> { pub fn get_component<T: Component>(
&self,
entity: Entity,
) -> Result<&'w T, QueryComponentError> {
let world = self.world; let world = self.world;
let entity_ref = world let entity_ref = world
.get_entity(entity) .get_entity(entity)
@ -511,7 +517,7 @@ where
/// ``` /// ```
/// ///
/// This can only be called for read-only queries, see [`Self::single_mut`] for write-queries. /// This can only be called for read-only queries, see [`Self::single_mut`] for write-queries.
pub fn single(&self) -> Result<<Q::Fetch as Fetch<'_, '_>>::Item, QuerySingleError> pub fn single(&'s self) -> Result<<Q::Fetch as Fetch<'w, 's>>::Item, QuerySingleError>
where where
Q::Fetch: ReadOnlyFetch, Q::Fetch: ReadOnlyFetch,
{ {

View File

@ -27,11 +27,14 @@ use std::{
/// ///
/// ``` /// ```
/// # use bevy_ecs::prelude::*; /// # use bevy_ecs::prelude::*;
/// use std::marker::PhantomData;
/// use bevy_ecs::system::SystemParam; /// use bevy_ecs::system::SystemParam;
/// ///
/// #[derive(SystemParam)] /// #[derive(SystemParam)]
/// struct MyParam<'a> { /// struct MyParam<'w, 's> {
/// foo: Res<'a, usize>, /// foo: Res<'w, usize>,
/// #[system_param(ignore)]
/// marker: PhantomData<&'s usize>,
/// } /// }
/// ///
/// fn my_system(param: MyParam) { /// fn my_system(param: MyParam) {
@ -41,7 +44,7 @@ use std::{
/// # my_system.system(); /// # my_system.system();
/// ``` /// ```
pub trait SystemParam: Sized { pub trait SystemParam: Sized {
type Fetch: for<'a> SystemParamFetch<'a>; type Fetch: for<'w, 's> SystemParamFetch<'w, 's>;
} }
/// The state of a [`SystemParam`]. /// 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`] /// This must only be implemented for [`SystemParamFetch`] impls that exclusively read the World passed in to [`SystemParamFetch::get_param`]
pub unsafe trait ReadOnlySystemParamFetch {} pub unsafe trait ReadOnlySystemParamFetch {}
pub trait SystemParamFetch<'a>: SystemParamState { pub trait SystemParamFetch<'world, 'state>: SystemParamState {
type Item; type Item;
/// # Safety /// # Safety
/// ///
/// This call might access any of the input parameters in an unsafe way. Make sure the data /// 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. /// access is safe in the context of the system scheduler.
unsafe fn get_param( unsafe fn get_param(
state: &'a mut Self, state: &'state mut Self,
system_meta: &SystemMeta, system_meta: &SystemMeta,
world: &'a World, world: &'world World,
change_tick: u32, change_tick: u32,
) -> Self::Item; ) -> 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 where
F::Fetch: FilterFetch, F::Fetch: FilterFetch,
{ {
@ -146,17 +149,18 @@ where
fn default_config() {} fn default_config() {}
} }
impl<'a, Q: WorldQuery + 'static, F: WorldQuery + 'static> SystemParamFetch<'a> for QueryState<Q, F> impl<'w, 's, Q: WorldQuery + 'static, F: WorldQuery + 'static> SystemParamFetch<'w, 's>
for QueryState<Q, F>
where where
F::Fetch: FilterFetch, F::Fetch: FilterFetch,
{ {
type Item = Query<'a, Q, F>; type Item = Query<'w, 's, Q, F>;
#[inline] #[inline]
unsafe fn get_param( unsafe fn get_param(
state: &'a mut Self, state: &'s mut Self,
system_meta: &SystemMeta, system_meta: &SystemMeta,
world: &'a World, world: &'w World,
change_tick: u32, change_tick: u32,
) -> Self::Item { ) -> Self::Item {
Query::new(world, state, system_meta.last_change_tick, change_tick) 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); query_type, filter_type, system_name, accesses);
} }
pub struct QuerySet<T>(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>(T); pub struct QuerySetState<T>(T);
impl_query_set!(); impl_query_set!();
@ -228,6 +238,10 @@ impl<'w, T: Component> Res<'w, T> {
self.ticks self.ticks
.is_changed(self.last_change_tick, self.change_tick) .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> { impl<'w, T: Component> Deref for Res<'w, T> {
@ -286,14 +300,14 @@ unsafe impl<T: Component> SystemParamState for ResState<T> {
fn default_config() {} fn default_config() {}
} }
impl<'a, T: Component> SystemParamFetch<'a> for ResState<T> { impl<'w, 's, T: Component> SystemParamFetch<'w, 's> for ResState<T> {
type Item = Res<'a, T>; type Item = Res<'w, T>;
#[inline] #[inline]
unsafe fn get_param( unsafe fn get_param(
state: &'a mut Self, state: &'s mut Self,
system_meta: &SystemMeta, system_meta: &SystemMeta,
world: &'a World, world: &'w World,
change_tick: u32, change_tick: u32,
) -> Self::Item { ) -> Self::Item {
let column = world let column = world
@ -334,14 +348,14 @@ unsafe impl<T: Component> SystemParamState for OptionResState<T> {
fn default_config() {} fn default_config() {}
} }
impl<'a, T: Component> SystemParamFetch<'a> for OptionResState<T> { impl<'w, 's, T: Component> SystemParamFetch<'w, 's> for OptionResState<T> {
type Item = Option<Res<'a, T>>; type Item = Option<Res<'w, T>>;
#[inline] #[inline]
unsafe fn get_param( unsafe fn get_param(
state: &'a mut Self, state: &'s mut Self,
system_meta: &SystemMeta, system_meta: &SystemMeta,
world: &'a World, world: &'w World,
change_tick: u32, change_tick: u32,
) -> Self::Item { ) -> Self::Item {
world world
@ -400,14 +414,14 @@ unsafe impl<T: Component> SystemParamState for ResMutState<T> {
fn default_config() {} fn default_config() {}
} }
impl<'a, T: Component> SystemParamFetch<'a> for ResMutState<T> { impl<'w, 's, T: Component> SystemParamFetch<'w, 's> for ResMutState<T> {
type Item = ResMut<'a, T>; type Item = ResMut<'w, T>;
#[inline] #[inline]
unsafe fn get_param( unsafe fn get_param(
state: &'a mut Self, state: &'s mut Self,
system_meta: &SystemMeta, system_meta: &SystemMeta,
world: &'a World, world: &'w World,
change_tick: u32, change_tick: u32,
) -> Self::Item { ) -> Self::Item {
let value = world let value = world
@ -447,14 +461,14 @@ unsafe impl<T: Component> SystemParamState for OptionResMutState<T> {
fn default_config() {} fn default_config() {}
} }
impl<'a, T: Component> SystemParamFetch<'a> for OptionResMutState<T> { impl<'w, 's, T: Component> SystemParamFetch<'w, 's> for OptionResMutState<T> {
type Item = Option<ResMut<'a, T>>; type Item = Option<ResMut<'w, T>>;
#[inline] #[inline]
unsafe fn get_param( unsafe fn get_param(
state: &'a mut Self, state: &'s mut Self,
system_meta: &SystemMeta, system_meta: &SystemMeta,
world: &'a World, world: &'w World,
change_tick: u32, change_tick: u32,
) -> Self::Item { ) -> Self::Item {
world world
@ -470,7 +484,7 @@ impl<'a, T: Component> SystemParamFetch<'a> for OptionResMutState<T> {
} }
} }
impl<'a> SystemParam for Commands<'a> { impl<'w, 's> SystemParam for Commands<'w, 's> {
type Fetch = CommandQueue; type Fetch = CommandQueue;
} }
@ -492,14 +506,14 @@ unsafe impl SystemParamState for CommandQueue {
fn default_config() {} fn default_config() {}
} }
impl<'a> SystemParamFetch<'a> for CommandQueue { impl<'w, 's> SystemParamFetch<'w, 's> for CommandQueue {
type Item = Commands<'a>; type Item = Commands<'w, 's>;
#[inline] #[inline]
unsafe fn get_param( unsafe fn get_param(
state: &'a mut Self, state: &'s mut Self,
_system_meta: &SystemMeta, _system_meta: &SystemMeta,
world: &'a World, world: &'w World,
_change_tick: u32, _change_tick: u32,
) -> Self::Item { ) -> Self::Item {
Commands::new(state, world) Commands::new(state, world)
@ -582,14 +596,14 @@ unsafe impl<T: Component + FromWorld> SystemParamState for LocalState<T> {
} }
} }
impl<'a, T: Component + FromWorld> SystemParamFetch<'a> for LocalState<T> { impl<'w, 's, T: Component + FromWorld> SystemParamFetch<'w, 's> for LocalState<T> {
type Item = Local<'a, T>; type Item = Local<'s, T>;
#[inline] #[inline]
unsafe fn get_param( unsafe fn get_param(
state: &'a mut Self, state: &'s mut Self,
_system_meta: &SystemMeta, _system_meta: &SystemMeta,
_world: &'a World, _world: &'w World,
_change_tick: u32, _change_tick: u32,
) -> Self::Item { ) -> Self::Item {
Local(&mut state.0) Local(&mut state.0)
@ -655,14 +669,14 @@ unsafe impl<T: Component> SystemParamState for RemovedComponentsState<T> {
fn default_config() {} fn default_config() {}
} }
impl<'a, T: Component> SystemParamFetch<'a> for RemovedComponentsState<T> { impl<'w, 's, T: Component> SystemParamFetch<'w, 's> for RemovedComponentsState<T> {
type Item = RemovedComponents<'a, T>; type Item = RemovedComponents<'w, T>;
#[inline] #[inline]
unsafe fn get_param( unsafe fn get_param(
state: &'a mut Self, state: &'s mut Self,
_system_meta: &SystemMeta, _system_meta: &SystemMeta,
world: &'a World, world: &'w World,
_change_tick: u32, _change_tick: u32,
) -> Self::Item { ) -> Self::Item {
RemovedComponents { RemovedComponents {
@ -770,14 +784,14 @@ unsafe impl<T: 'static> SystemParamState for NonSendState<T> {
fn default_config() {} fn default_config() {}
} }
impl<'a, T: 'static> SystemParamFetch<'a> for NonSendState<T> { impl<'w, 's, T: 'static> SystemParamFetch<'w, 's> for NonSendState<T> {
type Item = NonSend<'a, T>; type Item = NonSend<'w, T>;
#[inline] #[inline]
unsafe fn get_param( unsafe fn get_param(
state: &'a mut Self, state: &'s mut Self,
system_meta: &SystemMeta, system_meta: &SystemMeta,
world: &'a World, world: &'w World,
change_tick: u32, change_tick: u32,
) -> Self::Item { ) -> Self::Item {
world.validate_non_send_access::<T>(); world.validate_non_send_access::<T>();
@ -803,7 +817,7 @@ impl<'a, T: 'static> SystemParamFetch<'a> for NonSendState<T> {
/// The [`SystemParamState`] of `Option<NonSend<T>>`. /// The [`SystemParamState`] of `Option<NonSend<T>>`.
pub struct OptionNonSendState<T>(NonSendState<T>); pub struct OptionNonSendState<T>(NonSendState<T>);
impl<'a, T: Component> SystemParam for Option<NonSend<'a, T>> { impl<'w, T: Component> SystemParam for Option<NonSend<'w, T>> {
type Fetch = OptionNonSendState<T>; type Fetch = OptionNonSendState<T>;
} }
@ -820,14 +834,14 @@ unsafe impl<T: 'static> SystemParamState for OptionNonSendState<T> {
fn default_config() {} fn default_config() {}
} }
impl<'a, T: 'static> SystemParamFetch<'a> for OptionNonSendState<T> { impl<'w, 's, T: 'static> SystemParamFetch<'w, 's> for OptionNonSendState<T> {
type Item = Option<NonSend<'a, T>>; type Item = Option<NonSend<'w, T>>;
#[inline] #[inline]
unsafe fn get_param( unsafe fn get_param(
state: &'a mut Self, state: &'s mut Self,
system_meta: &SystemMeta, system_meta: &SystemMeta,
world: &'a World, world: &'w World,
change_tick: u32, change_tick: u32,
) -> Self::Item { ) -> Self::Item {
world.validate_non_send_access::<T>(); world.validate_non_send_access::<T>();
@ -889,14 +903,14 @@ unsafe impl<T: 'static> SystemParamState for NonSendMutState<T> {
fn default_config() {} fn default_config() {}
} }
impl<'a, T: 'static> SystemParamFetch<'a> for NonSendMutState<T> { impl<'w, 's, T: 'static> SystemParamFetch<'w, 's> for NonSendMutState<T> {
type Item = NonSendMut<'a, T>; type Item = NonSendMut<'w, T>;
#[inline] #[inline]
unsafe fn get_param( unsafe fn get_param(
state: &'a mut Self, state: &'s mut Self,
system_meta: &SystemMeta, system_meta: &SystemMeta,
world: &'a World, world: &'w World,
change_tick: u32, change_tick: u32,
) -> Self::Item { ) -> Self::Item {
world.validate_non_send_access::<T>(); world.validate_non_send_access::<T>();
@ -937,14 +951,14 @@ unsafe impl<T: 'static> SystemParamState for OptionNonSendMutState<T> {
fn default_config() {} fn default_config() {}
} }
impl<'a, T: 'static> SystemParamFetch<'a> for OptionNonSendMutState<T> { impl<'w, 's, T: 'static> SystemParamFetch<'w, 's> for OptionNonSendMutState<T> {
type Item = Option<NonSendMut<'a, T>>; type Item = Option<NonSendMut<'w, T>>;
#[inline] #[inline]
unsafe fn get_param( unsafe fn get_param(
state: &'a mut Self, state: &'s mut Self,
system_meta: &SystemMeta, system_meta: &SystemMeta,
world: &'a World, world: &'w World,
change_tick: u32, change_tick: u32,
) -> Self::Item { ) -> Self::Item {
world.validate_non_send_access::<T>(); world.validate_non_send_access::<T>();
@ -982,14 +996,14 @@ unsafe impl SystemParamState for ArchetypesState {
fn default_config() {} fn default_config() {}
} }
impl<'a> SystemParamFetch<'a> for ArchetypesState { impl<'w, 's> SystemParamFetch<'w, 's> for ArchetypesState {
type Item = &'a Archetypes; type Item = &'w Archetypes;
#[inline] #[inline]
unsafe fn get_param( unsafe fn get_param(
_state: &'a mut Self, _state: &'s mut Self,
_system_meta: &SystemMeta, _system_meta: &SystemMeta,
world: &'a World, world: &'w World,
_change_tick: u32, _change_tick: u32,
) -> Self::Item { ) -> Self::Item {
world.archetypes() world.archetypes()
@ -1017,14 +1031,14 @@ unsafe impl SystemParamState for ComponentsState {
fn default_config() {} fn default_config() {}
} }
impl<'a> SystemParamFetch<'a> for ComponentsState { impl<'w, 's> SystemParamFetch<'w, 's> for ComponentsState {
type Item = &'a Components; type Item = &'w Components;
#[inline] #[inline]
unsafe fn get_param( unsafe fn get_param(
_state: &'a mut Self, _state: &'s mut Self,
_system_meta: &SystemMeta, _system_meta: &SystemMeta,
world: &'a World, world: &'w World,
_change_tick: u32, _change_tick: u32,
) -> Self::Item { ) -> Self::Item {
world.components() world.components()
@ -1052,14 +1066,14 @@ unsafe impl SystemParamState for EntitiesState {
fn default_config() {} fn default_config() {}
} }
impl<'a> SystemParamFetch<'a> for EntitiesState { impl<'w, 's> SystemParamFetch<'w, 's> for EntitiesState {
type Item = &'a Entities; type Item = &'w Entities;
#[inline] #[inline]
unsafe fn get_param( unsafe fn get_param(
_state: &'a mut Self, _state: &'s mut Self,
_system_meta: &SystemMeta, _system_meta: &SystemMeta,
world: &'a World, world: &'w World,
_change_tick: u32, _change_tick: u32,
) -> Self::Item { ) -> Self::Item {
world.entities() world.entities()
@ -1087,14 +1101,14 @@ unsafe impl SystemParamState for BundlesState {
fn default_config() {} fn default_config() {}
} }
impl<'a> SystemParamFetch<'a> for BundlesState { impl<'w, 's> SystemParamFetch<'w, 's> for BundlesState {
type Item = &'a Bundles; type Item = &'w Bundles;
#[inline] #[inline]
unsafe fn get_param( unsafe fn get_param(
_state: &'a mut Self, _state: &'s mut Self,
_system_meta: &SystemMeta, _system_meta: &SystemMeta,
world: &'a World, world: &'w World,
_change_tick: u32, _change_tick: u32,
) -> Self::Item { ) -> Self::Item {
world.bundles() world.bundles()
@ -1127,13 +1141,13 @@ unsafe impl SystemParamState for SystemChangeTickState {
fn default_config() {} fn default_config() {}
} }
impl<'a> SystemParamFetch<'a> for SystemChangeTickState { impl<'w, 's> SystemParamFetch<'w, 's> for SystemChangeTickState {
type Item = SystemChangeTick; type Item = SystemChangeTick;
unsafe fn get_param( unsafe fn get_param(
_state: &mut Self, _state: &'s mut Self,
system_meta: &SystemMeta, system_meta: &SystemMeta,
_world: &World, _world: &'w World,
change_tick: u32, change_tick: u32,
) -> Self::Item { ) -> Self::Item {
SystemChangeTick { SystemChangeTick {
@ -1154,15 +1168,15 @@ macro_rules! impl_system_param_tuple {
#[allow(unused_variables)] #[allow(unused_variables)]
#[allow(non_snake_case)] #[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,)*); type Item = ($($param::Item,)*);
#[inline] #[inline]
#[allow(clippy::unused_unit)] #[allow(clippy::unused_unit)]
unsafe fn get_param( unsafe fn get_param(
state: &'a mut Self, state: &'s mut Self,
system_meta: &SystemMeta, system_meta: &SystemMeta,
world: &'a World, world: &'w World,
change_tick: u32, change_tick: u32,
) -> Self::Item { ) -> Self::Item {

View File

@ -4,9 +4,10 @@ use bevy_ecs::{
component::Component, component::Component,
entity::Entity, entity::Entity,
event::EventReader, event::EventReader,
prelude::QueryState,
query::Added, query::Added,
reflect::ReflectComponent, reflect::ReflectComponent,
system::{Query, QuerySet, Res}, system::{QuerySet, Res},
}; };
use bevy_math::{Mat4, Vec2, Vec3}; use bevy_math::{Mat4, Vec2, Vec3};
use bevy_reflect::{Reflect, ReflectDeserialize}; use bevy_reflect::{Reflect, ReflectDeserialize};
@ -70,8 +71,8 @@ pub fn camera_system<T: CameraProjection + Component>(
mut window_created_events: EventReader<WindowCreated>, mut window_created_events: EventReader<WindowCreated>,
windows: Res<Windows>, windows: Res<Windows>,
mut queries: QuerySet<( mut queries: QuerySet<(
Query<(Entity, &mut Camera, &mut T)>, QueryState<(Entity, &mut Camera, &mut T)>,
Query<Entity, Added<Camera>>, QueryState<Entity, Added<Camera>>,
)>, )>,
) { ) {
let mut changed_window_ids = Vec::new(); let mut changed_window_ids = Vec::new();
@ -99,7 +100,7 @@ pub fn camera_system<T: CameraProjection + Component>(
for entity in &mut queries.q1().iter() { for entity in &mut queries.q1().iter() {
added_cameras.push(entity); 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 let Some(window) = windows.get(camera.window) {
if changed_window_ids.contains(&window.id()) if changed_window_ids.contains(&window.id())
|| added_cameras.contains(&entity) || added_cameras.contains(&entity)

View File

@ -14,7 +14,7 @@ use bevy_ecs::{
system::{Query, Res, ResMut, SystemParam}, system::{Query, Res, ResMut, SystemParam},
}; };
use bevy_reflect::Reflect; use bevy_reflect::Reflect;
use std::{ops::Range, sync::Arc}; use std::{marker::PhantomData, ops::Range, sync::Arc};
use thiserror::Error; use thiserror::Error;
/// A queued command for the renderer /// A queued command for the renderer
@ -164,18 +164,20 @@ pub enum DrawError {
} }
#[derive(SystemParam)] #[derive(SystemParam)]
pub struct DrawContext<'a> { pub struct DrawContext<'w, 's> {
pub pipelines: ResMut<'a, Assets<PipelineDescriptor>>, pub pipelines: ResMut<'w, Assets<PipelineDescriptor>>,
pub shaders: ResMut<'a, Assets<Shader>>, pub shaders: ResMut<'w, Assets<Shader>>,
pub asset_render_resource_bindings: ResMut<'a, AssetRenderResourceBindings>, pub asset_render_resource_bindings: ResMut<'w, AssetRenderResourceBindings>,
pub pipeline_compiler: ResMut<'a, PipelineCompiler>, pub pipeline_compiler: ResMut<'w, PipelineCompiler>,
pub render_resource_context: Res<'a, Box<dyn RenderResourceContext>>, pub render_resource_context: Res<'w, Box<dyn RenderResourceContext>>,
pub shared_buffers: ResMut<'a, SharedBuffers>, pub shared_buffers: ResMut<'w, SharedBuffers>,
#[system_param(ignore)] #[system_param(ignore)]
pub current_pipeline: Option<Handle<PipelineDescriptor>>, pub current_pipeline: Option<Handle<PipelineDescriptor>>,
#[system_param(ignore)]
marker: PhantomData<&'s usize>,
} }
impl<'a> DrawContext<'a> { impl<'w, 's> DrawContext<'w, 's> {
pub fn get_uniform_buffer<T: RenderResource>( pub fn get_uniform_buffer<T: RenderResource>(
&mut self, &mut self,
render_resource: &T, render_resource: &T,

View File

@ -9,8 +9,9 @@ use bevy_core::cast_slice;
use bevy_ecs::{ use bevy_ecs::{
entity::Entity, entity::Entity,
event::EventReader, event::EventReader,
prelude::QueryState,
query::{Changed, With}, query::{Changed, With},
system::{Local, Query, QuerySet, Res}, system::{Local, QuerySet, Res},
world::Mut, world::Mut,
}; };
use bevy_math::*; use bevy_math::*;
@ -512,8 +513,8 @@ pub fn mesh_resource_provider_system(
meshes: Res<Assets<Mesh>>, meshes: Res<Assets<Mesh>>,
mut mesh_events: EventReader<AssetEvent<Mesh>>, mut mesh_events: EventReader<AssetEvent<Mesh>>,
mut queries: QuerySet<( mut queries: QuerySet<(
Query<&mut RenderPipelines, With<Handle<Mesh>>>, QueryState<&mut RenderPipelines, With<Handle<Mesh>>>,
Query<(Entity, &Handle<Mesh>, &mut RenderPipelines), Changed<Handle<Mesh>>>, QueryState<(Entity, &Handle<Mesh>, &mut RenderPipelines), Changed<Handle<Mesh>>>,
)>, )>,
) { ) {
let mut changed_meshes = HashSet::default(); 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) { if let Some(mesh_entities) = state.mesh_entities.get_mut(changed_mesh_handle) {
for entity in mesh_entities.entities.iter() { 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( update_entity_mesh(
render_resource_context, render_resource_context,
mesh, mesh,
@ -587,7 +588,7 @@ pub fn mesh_resource_provider_system(
} }
// handover buffers to pipeline // 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 let mesh_entities = state
.mesh_entities .mesh_entities
.entry(handle.clone_weak()) .entry(handle.clone_weak())

View File

@ -13,10 +13,9 @@ use bevy_app::EventReader;
use bevy_asset::{Asset, AssetEvent, Assets, Handle, HandleId}; use bevy_asset::{Asset, AssetEvent, Assets, Handle, HandleId};
use bevy_ecs::{ use bevy_ecs::{
entity::Entity, entity::Entity,
prelude::QueryState,
query::{Changed, Or, With}, query::{Changed, Or, With},
system::{ system::{BoxedSystem, ConfigurableSystem, Local, QuerySet, RemovedComponents, Res, ResMut},
BoxedSystem, ConfigurableSystem, Local, Query, QuerySet, RemovedComponents, Res, ResMut,
},
world::World, world::World,
}; };
use bevy_utils::HashMap; use bevy_utils::HashMap;
@ -437,8 +436,11 @@ fn render_resources_node_system<T: RenderResources>(
render_resource_context: Res<Box<dyn RenderResourceContext>>, render_resource_context: Res<Box<dyn RenderResourceContext>>,
removed: RemovedComponents<T>, removed: RemovedComponents<T>,
mut queries: QuerySet<( mut queries: QuerySet<(
Query<(Entity, &T, &Visible, &mut RenderPipelines), Or<(Changed<T>, Changed<Visible>)>>, QueryState<
Query<(Entity, &T, &Visible, &mut RenderPipelines)>, (Entity, &T, &Visible, &mut RenderPipelines),
Or<(Changed<T>, Changed<Visible>)>,
>,
QueryState<(Entity, &T, &Visible, &mut RenderPipelines)>,
)>, )>,
) { ) {
let state = state.deref_mut(); let state = state.deref_mut();
@ -446,7 +448,7 @@ fn render_resources_node_system<T: RenderResources>(
let render_resource_context = &**render_resource_context; let render_resource_context = &**render_resource_context;
uniform_buffer_arrays.begin_update(); uniform_buffer_arrays.begin_update();
// initialize uniform buffer arrays using the first RenderResources // 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); uniform_buffer_arrays.initialize(first, render_resource_context);
} }
@ -456,8 +458,7 @@ fn render_resources_node_system<T: RenderResources>(
// handle entities that were waiting for texture loads on the last update // handle entities that were waiting for texture loads on the last update
for entity in std::mem::take(&mut *entities_waiting_for_textures) { for entity in std::mem::take(&mut *entities_waiting_for_textures) {
if let Ok((entity, uniforms, _visible, mut render_pipelines)) = if let Ok((entity, uniforms, _visible, mut render_pipelines)) = queries.q1().get_mut(entity)
queries.q1_mut().get_mut(entity)
{ {
if !setup_uniform_texture_resources::<T>( if !setup_uniform_texture_resources::<T>(
uniforms, uniforms,
@ -469,7 +470,7 @@ fn render_resources_node_system<T: RenderResources>(
} }
} }
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 { if !visible.is_visible {
continue; continue;
} }
@ -498,8 +499,7 @@ fn render_resources_node_system<T: RenderResources>(
// if the buffer array was resized, write all entities to the new buffer, otherwise // if the buffer array was resized, write all entities to the new buffer, otherwise
// only write changes // only write changes
if resized { if resized {
for (entity, uniforms, visible, mut render_pipelines) in for (entity, uniforms, visible, mut render_pipelines) in queries.q1().iter_mut()
queries.q1_mut().iter_mut()
{ {
if !visible.is_visible { if !visible.is_visible {
continue; continue;
@ -515,8 +515,7 @@ fn render_resources_node_system<T: RenderResources>(
); );
} }
} else { } else {
for (entity, uniforms, visible, mut render_pipelines) in for (entity, uniforms, visible, mut render_pipelines) in queries.q0().iter_mut()
queries.q0_mut().iter_mut()
{ {
if !visible.is_visible { if !visible.is_visible {
continue; continue;
@ -621,8 +620,8 @@ fn asset_render_resources_node_system<T: RenderResources + Asset>(
render_resource_context: Res<Box<dyn RenderResourceContext>>, render_resource_context: Res<Box<dyn RenderResourceContext>>,
removed_handles: RemovedComponents<Handle<T>>, removed_handles: RemovedComponents<Handle<T>>,
mut queries: QuerySet<( mut queries: QuerySet<(
Query<(&Handle<T>, &mut RenderPipelines), Changed<Handle<T>>>, QueryState<(&Handle<T>, &mut RenderPipelines), Changed<Handle<T>>>,
Query<&mut RenderPipelines, With<Handle<T>>>, QueryState<&mut RenderPipelines, With<Handle<T>>>,
)>, )>,
) { ) {
let state = state.deref_mut(); let state = state.deref_mut();
@ -752,7 +751,7 @@ fn asset_render_resources_node_system<T: RenderResources + Asset>(
// update removed entity asset mapping // update removed entity asset mapping
for entity in removed_handles.iter() { 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 render_pipelines
.bindings .bindings
.remove_asset_with_type(TypeId::of::<T>()) .remove_asset_with_type(TypeId::of::<T>())
@ -760,7 +759,7 @@ fn asset_render_resources_node_system<T: RenderResources + Asset>(
} }
// update changed entity asset mapping // 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 render_pipelines
.bindings .bindings
.remove_asset_with_type(TypeId::of::<T>()); .remove_asset_with_type(TypeId::of::<T>());

View File

@ -8,9 +8,9 @@ use crate::{
use bevy_app::prelude::*; use bevy_app::prelude::*;
use bevy_asset::{Assets, Handle, HandleUntyped}; use bevy_asset::{Assets, Handle, HandleUntyped};
use bevy_ecs::{ use bevy_ecs::{
query::With, query::{QueryState, With},
reflect::ReflectComponent, reflect::ReflectComponent,
system::{Query, QuerySet, Res}, system::{QuerySet, Res},
world::Mut, world::Mut,
}; };
use bevy_reflect::{Reflect, TypeUuid}; use bevy_reflect::{Reflect, TypeUuid};
@ -62,8 +62,8 @@ pub fn draw_wireframes_system(
meshes: Res<Assets<Mesh>>, meshes: Res<Assets<Mesh>>,
wireframe_config: Res<WireframeConfig>, wireframe_config: Res<WireframeConfig>,
mut query: QuerySet<( mut query: QuerySet<(
Query<(&mut Draw, &mut RenderPipelines, &Handle<Mesh>, &Visible)>, QueryState<(&mut Draw, &mut RenderPipelines, &Handle<Mesh>, &Visible)>,
Query<(&mut Draw, &mut RenderPipelines, &Handle<Mesh>, &Visible), With<Wireframe>>, QueryState<(&mut Draw, &mut RenderPipelines, &Handle<Mesh>, &Visible), With<Wireframe>>,
)>, )>,
) { ) {
let iterator = |(mut draw, mut render_pipelines, mesh_handle, visible): ( let iterator = |(mut draw, mut render_pipelines, mesh_handle, visible): (
@ -123,8 +123,8 @@ pub fn draw_wireframes_system(
}; };
if wireframe_config.global { if wireframe_config.global {
query.q0_mut().iter_mut().for_each(iterator); query.q0().iter_mut().for_each(iterator);
} else { } else {
query.q1_mut().iter_mut().for_each(iterator); query.q1().iter_mut().for_each(iterator);
} }
} }

View File

@ -23,7 +23,7 @@ pub trait SpawnSceneCommands {
fn spawn_scene(&mut self, scene: Handle<Scene>); fn spawn_scene(&mut self, scene: Handle<Scene>);
} }
impl<'a> SpawnSceneCommands for Commands<'a> { impl<'w, 's> SpawnSceneCommands for Commands<'w, 's> {
fn spawn_scene(&mut self, scene_handle: Handle<Scene>) { fn spawn_scene(&mut self, scene_handle: Handle<Scene>) {
self.add(SpawnScene { scene_handle }); self.add(SpawnScene { scene_handle });
} }
@ -45,7 +45,7 @@ pub trait SpawnSceneAsChildCommands {
fn spawn_scene(&mut self, scene: Handle<Scene>) -> &mut Self; fn spawn_scene(&mut self, scene: Handle<Scene>) -> &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<Scene>) -> &mut Self { fn spawn_scene(&mut self, scene_handle: Handle<Scene>) -> &mut Self {
self.add_command(SpawnSceneAsChild { self.add_command(SpawnSceneAsChild {
scene_handle, scene_handle,

View File

@ -2,7 +2,7 @@ use bevy_asset::Assets;
use bevy_ecs::{ use bevy_ecs::{
bundle::Bundle, bundle::Bundle,
entity::Entity, entity::Entity,
query::{Changed, With, Without}, query::{Changed, QueryState, With, Without},
system::{Local, Query, QuerySet, Res, ResMut}, system::{Local, Query, QuerySet, Res, ResMut},
}; };
use bevy_math::{Size, Vec3}; use bevy_math::{Size, Vec3};
@ -136,12 +136,12 @@ pub fn text2d_system(
mut font_atlas_set_storage: ResMut<Assets<FontAtlasSet>>, mut font_atlas_set_storage: ResMut<Assets<FontAtlasSet>>,
mut text_pipeline: ResMut<DefaultTextPipeline>, mut text_pipeline: ResMut<DefaultTextPipeline>,
mut text_queries: QuerySet<( mut text_queries: QuerySet<(
Query<Entity, (With<MainPass>, Changed<Text>)>, QueryState<Entity, (With<MainPass>, Changed<Text>)>,
Query<(&Text, &mut Text2dSize), With<MainPass>>, QueryState<(&Text, &mut Text2dSize), With<MainPass>>,
)>, )>,
) { ) {
// Adds all entities where the text or the style has changed to the local queue // 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); queued_text.entities.push(entity);
} }
@ -157,7 +157,7 @@ pub fn text2d_system(
// Computes all text in the local queue // Computes all text in the local queue
let mut new_queue = Vec::new(); 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(..) { for entity in queued_text.entities.drain(..) {
if let Ok((text, mut calculated_size)) = query.get_mut(entity) { if let Ok((text, mut calculated_size)) = query.get_mut(entity) {
match text_pipeline.queue_text( match text_pipeline.queue_text(

View File

@ -40,8 +40,8 @@ pub struct PushChildren {
children: SmallVec<[Entity; 8]>, children: SmallVec<[Entity; 8]>,
} }
pub struct ChildBuilder<'a, 'b> { pub struct ChildBuilder<'w, 's, 'a> {
commands: &'b mut Commands<'a>, commands: &'a mut Commands<'w, 's>,
push_children: PushChildren, push_children: PushChildren,
} }
@ -71,14 +71,14 @@ impl Command for PushChildren {
} }
} }
impl<'a, 'b> ChildBuilder<'a, 'b> { impl<'w, 's, 'a> ChildBuilder<'w, 's, 'a> {
pub fn spawn_bundle(&mut self, bundle: impl Bundle) -> EntityCommands<'a, '_> { pub fn spawn_bundle(&mut self, bundle: impl Bundle) -> EntityCommands<'w, 's, '_> {
let e = self.commands.spawn_bundle(bundle); let e = self.commands.spawn_bundle(bundle);
self.push_children.children.push(e.id()); self.push_children.children.push(e.id());
e e
} }
pub fn spawn(&mut self) -> EntityCommands<'a, '_> { pub fn spawn(&mut self) -> EntityCommands<'w, 's, '_> {
let e = self.commands.spawn(); let e = self.commands.spawn();
self.push_children.children.push(e.id()); self.push_children.children.push(e.id());
e e
@ -100,7 +100,7 @@ pub trait BuildChildren {
fn insert_children(&mut self, index: usize, children: &[Entity]) -> &mut Self; 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 { fn with_children(&mut self, spawn_children: impl FnOnce(&mut ChildBuilder)) -> &mut Self {
let parent = self.id(); let parent = self.id();
let push_children = { let push_children = {

View File

@ -47,7 +47,7 @@ pub trait DespawnRecursiveExt {
fn despawn_recursive(&mut self); 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. /// Despawns the provided entity and its children.
fn despawn_recursive(&mut self) { fn despawn_recursive(&mut self) {
let entity = self.id(); let entity = self.id();

View File

@ -2,7 +2,7 @@ use crate::{CalculatedSize, Node, Style, Val};
use bevy_asset::Assets; use bevy_asset::Assets;
use bevy_ecs::{ use bevy_ecs::{
entity::Entity, entity::Entity,
query::{Changed, Or, With, Without}, query::{Changed, Or, QueryState, With, Without},
system::{Local, Query, QuerySet, Res, ResMut}, system::{Local, Query, QuerySet, Res, ResMut},
}; };
use bevy_math::Size; use bevy_math::Size;
@ -53,9 +53,9 @@ pub fn text_system(
mut font_atlas_set_storage: ResMut<Assets<FontAtlasSet>>, mut font_atlas_set_storage: ResMut<Assets<FontAtlasSet>>,
mut text_pipeline: ResMut<DefaultTextPipeline>, mut text_pipeline: ResMut<DefaultTextPipeline>,
mut text_queries: QuerySet<( mut text_queries: QuerySet<(
Query<Entity, Or<(Changed<Text>, Changed<Style>)>>, QueryState<Entity, Or<(Changed<Text>, Changed<Style>)>>,
Query<Entity, (With<Text>, With<Style>)>, QueryState<Entity, (With<Text>, With<Style>)>,
Query<(&Text, &Style, &mut CalculatedSize)>, QueryState<(&Text, &Style, &mut CalculatedSize)>,
)>, )>,
) { ) {
let scale_factor = if let Some(window) = windows.get_primary() { let scale_factor = if let Some(window) = windows.get_primary() {
@ -86,7 +86,7 @@ pub fn text_system(
// Computes all text in the local queue // Computes all text in the local queue
let mut new_queue = Vec::new(); let mut new_queue = Vec::new();
let query = text_queries.q2_mut(); let mut query = text_queries.q2();
for entity in queued_text.entities.drain(..) { for entity in queued_text.entities.drain(..) {
if let Ok((text, style, mut calculated_size)) = query.get_mut(entity) { if let Ok((text, style, mut calculated_size)) = query.get_mut(entity) {
let node_size = Size::new( let node_size = Size::new(

View File

@ -17,12 +17,12 @@ pub struct PlayerCount(usize);
/// ///
/// In this example, it includes a query and a mutable resource. /// In this example, it includes a query and a mutable resource.
#[derive(SystemParam)] #[derive(SystemParam)]
struct PlayerCounter<'a> { struct PlayerCounter<'w, 's> {
players: Query<'a, &'static Player>, players: Query<'w, 's, &'static Player>,
count: ResMut<'a, PlayerCount>, count: ResMut<'w, PlayerCount>,
} }
impl<'a> PlayerCounter<'a> { impl<'w, 's> PlayerCounter<'w, 's> {
fn count(&mut self) { fn count(&mut self) {
self.count.0 = self.players.iter().len(); self.count.0 = self.players.iter().len();
} }

View File

@ -248,14 +248,18 @@ fn move_player(
fn focus_camera( fn focus_camera(
time: Res<Time>, time: Res<Time>,
mut game: ResMut<Game>, mut game: ResMut<Game>,
mut transforms: QuerySet<(Query<(&mut Transform, &Camera)>, Query<&Transform>)>, mut transforms: QuerySet<(
QueryState<(&mut Transform, &Camera)>,
QueryState<&Transform>,
)>,
) { ) {
const SPEED: f32 = 2.0; const SPEED: f32 = 2.0;
// if there is both a player and a bonus, target the mid-point of them // if there is both a player and a bonus, target the mid-point of them
if let (Some(player_entity), Some(bonus_entity)) = (game.player.entity, game.bonus.entity) { if let (Some(player_entity), Some(bonus_entity)) = (game.player.entity, game.bonus.entity) {
let transform_query = transforms.q1();
if let (Ok(player_transform), Ok(bonus_transform)) = ( if let (Ok(player_transform), Ok(bonus_transform)) = (
transforms.q1().get(player_entity), transform_query.get(player_entity),
transforms.q1().get(bonus_entity), transform_query.get(bonus_entity),
) { ) {
game.camera_should_focus = player_transform game.camera_should_focus = player_transform
.translation .translation
@ -280,7 +284,7 @@ fn focus_camera(
game.camera_is_focus += camera_motion; game.camera_is_focus += camera_motion;
} }
// look at that new camera's actual focus // look at that new camera's actual focus
for (mut transform, camera) in transforms.q0_mut().iter_mut() { for (mut transform, camera) in transforms.q0().iter_mut() {
if camera.name == Some(CAMERA_3D.to_string()) { if camera.name == Some(CAMERA_3D.to_string()) {
*transform = transform.looking_at(game.camera_is_focus, Vec3::Y); *transform = transform.looking_at(game.camera_is_focus, Vec3::Y);
} }