From f8c9a73f24a859e391353b773d0fd56cddc29448 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=8Fvar=20K=C3=A4llstr=C3=B6m?= Date: Thu, 2 Sep 2021 13:52:14 +0200 Subject: [PATCH 01/34] fix get_conflicts to return every conflict. added get_conflicts_set --- crates/bevy_ecs/src/query/access.rs | 21 ++++++++++++++++++--- 1 file changed, 18 insertions(+), 3 deletions(-) diff --git a/crates/bevy_ecs/src/query/access.rs b/crates/bevy_ecs/src/query/access.rs index 25c1f39054008..fe95f602269ef 100644 --- a/crates/bevy_ecs/src/query/access.rs +++ b/crates/bevy_ecs/src/query/access.rs @@ -207,16 +207,31 @@ impl FilteredAccessSet { pub fn get_conflicts(&self, filtered_access: &FilteredAccess) -> Vec { // if combined unfiltered access is incompatible, check each filtered access for // compatibility + let mut conflicts = HashSet::::default(); if !filtered_access.access.is_compatible(&self.combined_access) { for current_filtered_access in self.filtered_accesses.iter() { if !current_filtered_access.is_compatible(filtered_access) { - return current_filtered_access + conflicts.extend(current_filtered_access .access - .get_conflicts(&filtered_access.access); + .get_conflicts(&filtered_access.access).iter().map(|ind| ind.sparse_set_index())); } } } - Vec::new() + conflicts.iter().map(|ind| T::get_sparse_set_index(*ind)).collect() + } + + pub fn get_conflicts_set(&self, filtered_access_set: &FilteredAccessSet) -> Vec { + // if combined unfiltered access is incompatible, check each filtered access for + // compatibility with the set + let mut conflicts = HashSet::::default(); + if !filtered_access_set.combined_access.is_compatible(&self.combined_access) { + for current_filtered_access in filtered_access_set.filtered_accesses.iter() { + if !current_filtered_access.is_compatible(current_filtered_access) { + conflicts.extend(self.get_conflicts(¤t_filtered_access).iter().map(|ind| ind.sparse_set_index())); + } + } + } + conflicts.iter().map(|ind| T::get_sparse_set_index(*ind)).collect() } pub fn add(&mut self, filtered_access: FilteredAccess) { From 3149b56ace7e1c37f99c885ff9023c52e895799b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=8Fvar=20K=C3=A4llstr=C3=B6m?= Date: Thu, 2 Sep 2021 13:52:34 +0200 Subject: [PATCH 02/34] add extend method to `FilteredAccessSet` --- crates/bevy_ecs/src/query/access.rs | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/crates/bevy_ecs/src/query/access.rs b/crates/bevy_ecs/src/query/access.rs index fe95f602269ef..9542ad8c4981d 100644 --- a/crates/bevy_ecs/src/query/access.rs +++ b/crates/bevy_ecs/src/query/access.rs @@ -1,6 +1,6 @@ use crate::storage::SparseSetIndex; use fixedbitset::FixedBitSet; -use std::marker::PhantomData; +use std::{collections::HashSet, marker::PhantomData}; /// `Access` keeps track of read and write accesses to values within a collection. /// @@ -238,6 +238,11 @@ impl FilteredAccessSet { self.combined_access.extend(&filtered_access.access); self.filtered_accesses.push(filtered_access); } + + pub fn extend(&mut self, filtered_access_set: FilteredAccessSet) { + self.combined_access.extend(&filtered_access_set.combined_access); + self.filtered_accesses.extend(filtered_access_set.filtered_accesses); + } } impl Default for FilteredAccessSet { From 2501b973071af3ecfa6f9de1ee9331ea738ba7f5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=8Fvar=20K=C3=A4llstr=C3=B6m?= Date: Thu, 2 Sep 2021 13:56:15 +0200 Subject: [PATCH 03/34] impl Into for FilteredAccess --- crates/bevy_ecs/src/query/access.rs | 45 +++++++++++++++++++++++------ 1 file changed, 36 insertions(+), 9 deletions(-) diff --git a/crates/bevy_ecs/src/query/access.rs b/crates/bevy_ecs/src/query/access.rs index 9542ad8c4981d..867c71ea4d851 100644 --- a/crates/bevy_ecs/src/query/access.rs +++ b/crates/bevy_ecs/src/query/access.rs @@ -146,6 +146,14 @@ impl Default for FilteredAccess { } } +impl Into> for FilteredAccess { + fn into(self) -> FilteredAccessSet { + let mut base = FilteredAccessSet::::default(); + base.add(self); + base + } +} + impl FilteredAccess { #[inline] pub fn access(&self) -> &Access { @@ -211,27 +219,44 @@ impl FilteredAccessSet { if !filtered_access.access.is_compatible(&self.combined_access) { for current_filtered_access in self.filtered_accesses.iter() { if !current_filtered_access.is_compatible(filtered_access) { - conflicts.extend(current_filtered_access - .access - .get_conflicts(&filtered_access.access).iter().map(|ind| ind.sparse_set_index())); + conflicts.extend( + current_filtered_access + .access + .get_conflicts(&filtered_access.access) + .iter() + .map(|ind| ind.sparse_set_index()), + ); } } } - conflicts.iter().map(|ind| T::get_sparse_set_index(*ind)).collect() + conflicts + .iter() + .map(|ind| T::get_sparse_set_index(*ind)) + .collect() } pub fn get_conflicts_set(&self, filtered_access_set: &FilteredAccessSet) -> Vec { // if combined unfiltered access is incompatible, check each filtered access for // compatibility with the set let mut conflicts = HashSet::::default(); - if !filtered_access_set.combined_access.is_compatible(&self.combined_access) { + if !filtered_access_set + .combined_access + .is_compatible(&self.combined_access) + { for current_filtered_access in filtered_access_set.filtered_accesses.iter() { if !current_filtered_access.is_compatible(current_filtered_access) { - conflicts.extend(self.get_conflicts(¤t_filtered_access).iter().map(|ind| ind.sparse_set_index())); + conflicts.extend( + self.get_conflicts(¤t_filtered_access) + .iter() + .map(|ind| ind.sparse_set_index()), + ); } } } - conflicts.iter().map(|ind| T::get_sparse_set_index(*ind)).collect() + conflicts + .iter() + .map(|ind| T::get_sparse_set_index(*ind)) + .collect() } pub fn add(&mut self, filtered_access: FilteredAccess) { @@ -240,8 +265,10 @@ impl FilteredAccessSet { } pub fn extend(&mut self, filtered_access_set: FilteredAccessSet) { - self.combined_access.extend(&filtered_access_set.combined_access); - self.filtered_accesses.extend(filtered_access_set.filtered_accesses); + self.combined_access + .extend(&filtered_access_set.combined_access); + self.filtered_accesses + .extend(filtered_access_set.filtered_accesses); } } From 6ab43ea1aeef6e74850f4e3e5619590c8b591c90 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=8Fvar=20K=C3=A4llstr=C3=B6m?= Date: Thu, 2 Sep 2021 14:00:35 +0200 Subject: [PATCH 04/34] refactor SystemParamState init, added methods --- crates/bevy_ecs/macros/src/lib.rs | 34 ++- crates/bevy_ecs/src/system/system_param.rs | 295 ++++++++++++++++++--- 2 files changed, 285 insertions(+), 44 deletions(-) diff --git a/crates/bevy_ecs/macros/src/lib.rs b/crates/bevy_ecs/macros/src/lib.rs index ed6fd79f95e8f..1d092190d2a45 100644 --- a/crates/bevy_ecs/macros/src/lib.rs +++ b/crates/bevy_ecs/macros/src/lib.rs @@ -229,11 +229,9 @@ pub fn impl_query_set(_input: TokenStream) -> TokenStream { #( let mut #query = QueryState::<#query, #filter>::new(world); assert_component_access_compatibility( - &system_meta.name, - std::any::type_name::<#query>(), - std::any::type_name::<#filter>(), - &system_meta.component_access_set, - &#query.component_access, + &system_meta, + std::any::type_name::>(), + &#query, world, ); )* @@ -248,6 +246,24 @@ pub fn impl_query_set(_input: TokenStream) -> TokenStream { QuerySetState((#(#query,)*)) } + fn archetype_component_access(&self) -> Access { + let (#(#query,)*) = &self.0; + let mut combined_access = Access::::default(); + #({ + combined_access.extend(&#query.archetype_component_access()); + })*; + combined_access + } + + fn component_access_set(&self) -> FilteredAccessSet { + let (#(#query,)*) = &self.0; + let mut combined_access = FilteredAccessSet::::default(); + #({ + combined_access.extend(#query.component_access_set()); + })*; + combined_access + } + fn new_archetype(&mut self, archetype: &Archetype, system_meta: &mut SystemMeta) { let (#(#query,)*) = &mut self.0; #( @@ -396,6 +412,14 @@ pub fn derive_system_param(input: TokenStream) -> TokenStream { } } + fn archetype_component_access(&self) -> #path::query::Access<#path::archetype::ArchetypeComponentId> { + self.state.archetype_component_access() + } + + fn component_access_set(&self) -> #path::query::FilteredAccessSet<#path::component::ComponentId> { + self.state.component_access_set() + } + fn new_archetype(&mut self, archetype: &#path::archetype::Archetype, system_meta: &mut #path::system::SystemMeta) { self.state.new_archetype(archetype, system_meta) } diff --git a/crates/bevy_ecs/src/system/system_param.rs b/crates/bevy_ecs/src/system/system_param.rs index af52e24d7bec4..6092a96ea1c00 100644 --- a/crates/bevy_ecs/src/system/system_param.rs +++ b/crates/bevy_ecs/src/system/system_param.rs @@ -1,12 +1,13 @@ pub use crate::change_detection::{NonSendMut, ResMut}; use crate::{ - archetype::{Archetype, Archetypes}, + archetype::{Archetype, ArchetypeComponentId, Archetypes}, bundle::Bundles, change_detection::Ticks, component::{Component, ComponentId, ComponentTicks, Components}, entity::{Entities, Entity}, query::{ - FilterFetch, FilteredAccess, FilteredAccessSet, QueryState, ReadOnlyFetch, WorldQuery, + Access, FilterFetch, FilteredAccess, FilteredAccessSet, QueryState, ReadOnlyFetch, + WorldQuery, }, system::{CommandQueue, Commands, Query, SystemMeta}, world::{FromWorld, World}, @@ -54,10 +55,11 @@ pub type SystemParamItem<'w, 's, P> = <

::Fetch as SystemParamF /// /// # Safety /// -/// It is the implementor's responsibility to ensure `system_meta` is populated with the _exact_ +/// It is the implementor's responsibility to +/// 1. ensure `system_meta` is populated with the _exact_ /// [`World`] access used by the `SystemParamState` (and associated [`SystemParamFetch`]). -/// Additionally, it is the implementor's responsibility to ensure there is no -/// conflicting access across all SystemParams. +/// 2. ensure there is no conflicting access across all SystemParams. +/// 3. ensure that `archetype_component_access` and `component_access_set` correctly returns the accesses done by the parameter. pub unsafe trait SystemParamState: Send + Sync + 'static { /// Values of this type can be used to adjust the behavior of the /// system parameter. For instance, this can be used to pass @@ -72,7 +74,10 @@ pub unsafe trait SystemParamState: Send + Sync + 'static { /// See [`FunctionSystem::config`](super::FunctionSystem::config) /// for more information and examples. type Config: Send + Sync; + fn archetype_component_access(&self) -> Access; + fn component_access_set(&self) -> FilteredAccessSet; fn init(world: &mut World, system_meta: &mut SystemMeta, config: Self::Config) -> Self; + #[inline] fn new_archetype(&mut self, _archetype: &Archetype, _system_meta: &mut SystemMeta) {} #[inline] @@ -87,7 +92,7 @@ pub unsafe trait SystemParamState: Send + Sync + 'static { pub unsafe trait ReadOnlySystemParamFetch {} pub trait SystemParamFetch<'world, 'state>: SystemParamState { - type Item; + type Item: SystemParam; /// # Safety /// /// This call might access any of the input parameters in an unsafe way. Make sure the data @@ -126,22 +131,28 @@ where fn init(world: &mut World, system_meta: &mut SystemMeta, _config: Self::Config) -> Self { let state = QueryState::new(world); assert_component_access_compatibility( - &system_meta.name, - std::any::type_name::(), - std::any::type_name::(), - &system_meta.component_access_set, - &state.component_access, + &system_meta, + std::any::type_name::>(), + &state, world, ); system_meta .component_access_set - .add(state.component_access.clone()); + .extend(state.component_access_set()); system_meta .archetype_component_access - .extend(&state.archetype_component_access); + .extend(&state.archetype_component_access()); state } + fn archetype_component_access(&self) -> Access { + self.archetype_component_access.clone() + } + + fn component_access_set(&self) -> FilteredAccessSet { + self.component_access.clone().into() + } + fn new_archetype(&mut self, archetype: &Archetype, system_meta: &mut SystemMeta) { self.new_archetype(archetype); system_meta @@ -171,14 +182,15 @@ where } fn assert_component_access_compatibility( - system_name: &str, - query_type: &'static str, - filter_type: &'static str, - system_access: &FilteredAccessSet, - current: &FilteredAccess, + system_meta: &SystemMeta, + param_type: &'static str, + state: &impl SystemParamState, world: &World, ) { - let mut conflicts = system_access.get_conflicts(current); + let system_name = &system_meta.name; + let mut conflicts = system_meta + .component_access_set + .get_conflicts_set(&state.component_access_set()); if conflicts.is_empty() { return; } @@ -271,6 +283,7 @@ impl<'w, T: Resource> AsRef for Res<'w, T> { /// The [`SystemParamState`] of [`Res`]. pub struct ResState { + archetype_component_id: ArchetypeComponentId, component_id: ComponentId, marker: PhantomData, } @@ -298,13 +311,37 @@ unsafe impl SystemParamState for ResState { let archetype_component_id = resource_archetype .get_archetype_component_id(component_id) .unwrap(); - system_meta - .archetype_component_access - .add_read(archetype_component_id); - Self { + + let state = Self { + archetype_component_id, component_id, marker: PhantomData, - } + }; + assert_component_access_compatibility( + &system_meta, + std::any::type_name::>(), + &state, + world, + ); + system_meta + .component_access_set + .extend(state.component_access_set()); + system_meta + .archetype_component_access + .extend(&state.archetype_component_access()); + state + } + + fn archetype_component_access(&self) -> Access { + let mut base_access = Access::::default(); + base_access.add_read(self.archetype_component_id); + base_access + } + + fn component_access_set(&self) -> FilteredAccessSet { + let mut base_access = FilteredAccess::default(); + base_access.add_read(self.component_id); + base_access.into() } fn default_config() {} @@ -356,6 +393,14 @@ unsafe impl SystemParamState for OptionResState { Self(ResState::init(world, system_meta, ())) } + fn archetype_component_access(&self) -> Access { + self.0.archetype_component_access() + } + + fn component_access_set(&self) -> FilteredAccessSet { + self.0.component_access_set() + } + fn default_config() {} } @@ -383,6 +428,7 @@ impl<'w, 's, T: Resource> SystemParamFetch<'w, 's> for OptionResState { /// The [`SystemParamState`] of [`ResMut`]. pub struct ResMutState { component_id: ComponentId, + archetype_component_id: ArchetypeComponentId, marker: PhantomData, } @@ -413,13 +459,37 @@ unsafe impl SystemParamState for ResMutState { let archetype_component_id = resource_archetype .get_archetype_component_id(component_id) .unwrap(); - system_meta - .archetype_component_access - .add_write(archetype_component_id); - Self { + + let state = Self { + archetype_component_id, component_id, marker: PhantomData, - } + }; + assert_component_access_compatibility( + &system_meta, + std::any::type_name::>(), + &state, + world, + ); + system_meta + .component_access_set + .extend(state.component_access_set()); + system_meta + .archetype_component_access + .extend(&state.archetype_component_access()); + state + } + + fn archetype_component_access(&self) -> Access { + let mut base_access = Access::::default(); + base_access.add_write(self.archetype_component_id); + base_access + } + + fn component_access_set(&self) -> FilteredAccessSet { + let mut base_access = FilteredAccess::default(); + base_access.add_write(self.component_id); + base_access.into() } fn default_config() {} @@ -470,6 +540,14 @@ unsafe impl SystemParamState for OptionResMutState { Self(ResMutState::init(world, system_meta, ())) } + fn archetype_component_access(&self) -> Access { + self.0.archetype_component_access() + } + + fn component_access_set(&self) -> FilteredAccessSet { + self.0.component_access_set() + } + fn default_config() {} } @@ -515,6 +593,14 @@ unsafe impl SystemParamState for CommandQueue { self.apply(world); } + fn archetype_component_access(&self) -> Access { + Default::default() + } + + fn component_access_set(&self) -> FilteredAccessSet { + Default::default() + } + fn default_config() {} } @@ -603,6 +689,14 @@ unsafe impl SystemParamState for LocalState { Self(config.unwrap_or_else(|| T::from_world(world))) } + fn component_access_set(&self) -> FilteredAccessSet { + Default::default() + } + + fn archetype_component_access(&self) -> Access { + Default::default() + } + fn default_config() -> Option { None } @@ -680,6 +774,14 @@ unsafe impl SystemParamState for RemovedComponentsState { } } + fn component_access_set(&self) -> FilteredAccessSet { + Default::default() + } + + fn archetype_component_access(&self) -> Access { + Default::default() + } + fn default_config() {} } @@ -757,6 +859,7 @@ impl<'w, T> Deref for NonSend<'w, T> { /// The [`SystemParamState`] of [`NonSend`]. pub struct NonSendState { + archetype_component_id: ArchetypeComponentId, component_id: ComponentId, marker: PhantomData T>, } @@ -786,13 +889,37 @@ unsafe impl SystemParamState for NonSendState { let archetype_component_id = resource_archetype .get_archetype_component_id(component_id) .unwrap(); - system_meta - .archetype_component_access - .add_read(archetype_component_id); - Self { + let state = Self { + archetype_component_id, component_id, marker: PhantomData, - } + }; + + assert_component_access_compatibility( + &system_meta, + std::any::type_name::>(), + &state, + world, + ); + system_meta + .component_access_set + .extend(state.component_access_set()); + system_meta + .archetype_component_access + .extend(&state.archetype_component_access()); + state + } + + fn archetype_component_access(&self) -> Access { + let mut base_access = Access::::default(); + base_access.add_read(self.archetype_component_id); + base_access + } + + fn component_access_set(&self) -> FilteredAccessSet { + let mut base_access = FilteredAccess::default(); + base_access.add_read(self.component_id); + base_access.into() } fn default_config() {} @@ -846,6 +973,14 @@ unsafe impl SystemParamState for OptionNonSendState { Self(NonSendState::init(world, system_meta, ())) } + fn archetype_component_access(&self) -> Access { + self.0.archetype_component_access() + } + + fn component_access_set(&self) -> FilteredAccessSet { + self.0.component_access_set() + } + fn default_config() {} } @@ -873,6 +1008,7 @@ impl<'w, 's, T: 'static> SystemParamFetch<'w, 's> for OptionNonSendState { /// The [`SystemParamState`] of [`NonSendMut`]. pub struct NonSendMutState { + archetype_component_id: ArchetypeComponentId, component_id: ComponentId, marker: PhantomData T>, } @@ -906,13 +1042,37 @@ unsafe impl SystemParamState for NonSendMutState { let archetype_component_id = resource_archetype .get_archetype_component_id(component_id) .unwrap(); - system_meta - .archetype_component_access - .add_write(archetype_component_id); - Self { + let state = Self { + archetype_component_id, component_id, marker: PhantomData, - } + }; + + assert_component_access_compatibility( + &system_meta, + std::any::type_name::>(), + &state, + world, + ); + system_meta + .component_access_set + .extend(state.component_access_set()); + system_meta + .archetype_component_access + .extend(&state.archetype_component_access()); + state + } + + fn archetype_component_access(&self) -> Access { + let mut base_access = Access::::default(); + base_access.add_write(self.archetype_component_id); + base_access + } + + fn component_access_set(&self) -> FilteredAccessSet { + let mut base_access = FilteredAccess::default(); + base_access.add_write(self.component_id); + base_access.into() } fn default_config() {} @@ -964,6 +1124,14 @@ unsafe impl SystemParamState for OptionNonSendMutState { Self(NonSendMutState::init(world, system_meta, ())) } + fn component_access_set(&self) -> FilteredAccessSet { + Default::default() + } + + fn archetype_component_access(&self) -> Access { + Default::default() + } + fn default_config() {} } @@ -1009,6 +1177,14 @@ unsafe impl SystemParamState for ArchetypesState { Self } + fn component_access_set(&self) -> FilteredAccessSet { + Default::default() + } + + fn archetype_component_access(&self) -> Access { + Default::default() + } + fn default_config() {} } @@ -1044,6 +1220,14 @@ unsafe impl SystemParamState for ComponentsState { Self } + fn component_access_set(&self) -> FilteredAccessSet { + Default::default() + } + + fn archetype_component_access(&self) -> Access { + Default::default() + } + fn default_config() {} } @@ -1079,6 +1263,14 @@ unsafe impl SystemParamState for EntitiesState { Self } + fn component_access_set(&self) -> FilteredAccessSet { + Default::default() + } + + fn archetype_component_access(&self) -> Access { + Default::default() + } + fn default_config() {} } @@ -1114,6 +1306,14 @@ unsafe impl SystemParamState for BundlesState { Self } + fn component_access_set(&self) -> FilteredAccessSet { + Default::default() + } + + fn archetype_component_access(&self) -> Access { + Default::default() + } + fn default_config() {} } @@ -1154,6 +1354,14 @@ unsafe impl SystemParamState for SystemChangeTickState { Self {} } + fn component_access_set(&self) -> FilteredAccessSet { + Default::default() + } + + fn archetype_component_access(&self) -> Access { + Default::default() + } + fn default_config() {} } @@ -1211,6 +1419,15 @@ macro_rules! impl_system_param_tuple { (($($param::init(_world, _system_meta, $param),)*)) } + + fn component_access_set(&self) -> FilteredAccessSet { + Default::default() + } + + fn archetype_component_access(&self) -> Access { + Default::default() + } + #[inline] fn new_archetype(&mut self, _archetype: &Archetype, _system_meta: &mut SystemMeta) { let ($($param,)*) = self; From 79fb544a7aa6ae91501e034bd19a4a08d1617d2b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=8Fvar=20K=C3=A4llstr=C3=B6m?= Date: Thu, 2 Sep 2021 14:06:10 +0200 Subject: [PATCH 05/34] add and impl ParamSet --- crates/bevy_ecs/macros/src/lib.rs | 131 ++++++++++++++++++ crates/bevy_ecs/src/query/access.rs | 2 +- crates/bevy_ecs/src/system/function_system.rs | 1 + crates/bevy_ecs/src/system/system_param.rs | 12 +- 4 files changed, 144 insertions(+), 2 deletions(-) diff --git a/crates/bevy_ecs/macros/src/lib.rs b/crates/bevy_ecs/macros/src/lib.rs index 1d092190d2a45..9b3779fc116d3 100644 --- a/crates/bevy_ecs/macros/src/lib.rs +++ b/crates/bevy_ecs/macros/src/lib.rs @@ -308,6 +308,137 @@ pub fn impl_query_set(_input: TokenStream) -> TokenStream { tokens } +#[proc_macro] +pub fn impl_param_set(_input: TokenStream) -> TokenStream { + let mut tokens = TokenStream::new(); + let max_params = 4; + let params = get_idents(|i| format!("P{}", i), max_params); + let params_fetch = get_idents(|i| format!("PF{}", i), max_params); + let values = get_idents(|i| format!("p{}", i), max_params); + let mut param_fn_muts = Vec::new(); + for i in 0..max_params { + let param = ¶ms[i]; + let fn_name = Ident::new(&format!("p{}", i), Span::call_site()); + let index = Index::from(i); + param_fn_muts.push(quote! { + pub fn #fn_name<'a>(&'a mut self) -> <#param::Fetch as SystemParamFetch<'a, 'a>>::Item { + // SAFE: systems run without conflicts with other systems. + // Conflicting queries in ParamSet are not accessible at the same time + // ParamSets are guaranteed to not conflict with other SystemParams + unsafe { + <#param::Fetch as SystemParamFetch<'a, 'a>>::get_param(&mut self.param_states.#index, &self.system_meta, self.world, self.change_tick) + } + } + }); + } + + for param_count in 1..=max_params { + let param = ¶ms[0..param_count]; + let param_fetch = ¶ms_fetch[0..param_count]; + let value = &values[0..param_count]; + let param_fn_mut = ¶m_fn_muts[0..param_count]; + tokens.extend(TokenStream::from(quote! { + impl<'w, 's, #(#param: SystemParam,)*> SystemParam for ParamSet<'w, 's, (#(#param,)*)> + { + type Fetch = ParamSetState<(#(#param::Fetch,)*)>; + } + + // SAFE: All Queries are constrained to ReadOnlyFetch, so World is only read + + unsafe impl<#(#param_fetch: for<'w1, 's1> SystemParamFetch<'w1, 's1>,)*> ReadOnlySystemParamFetch for ParamSetState<(#(#param_fetch,)*)> + where #(#param_fetch: ReadOnlySystemParamFetch,)* + { } + + // SAFE: Relevant query ComponentId and ArchetypeComponentId access is applied to SystemMeta. If any QueryState conflicts + // with any prior access, a panic will occur. + + unsafe impl<#(#param_fetch: for<'w1, 's1> SystemParamFetch<'w1, 's1>,)*> SystemParamState for ParamSetState<(#(#param_fetch,)*)> + { + type Config = (#(#param_fetch::Config,)*); + + + fn init(world: &mut World, system_meta: &mut SystemMeta, config: Self::Config) -> Self { + let (#(#value,)*) = config; + #( + // Pretend to add each param to the system alone, see if it conflicts + let #param = #param_fetch::init(world, &mut system_meta.clone(), #value); + )* + #( + system_meta + .component_access_set + .extend(#param.component_access_set()); + system_meta + .archetype_component_access + .extend(&#param.archetype_component_access()); + )* + ParamSetState((#(#param,)*)) + } + + fn new_archetype(&mut self, archetype: &Archetype, system_meta: &mut SystemMeta) { + let (#(#param,)*) = &mut self.0; + #( + #param.new_archetype(archetype, system_meta); + // system_meta + // .archetype_component_access + // .extend(&#param.archetype_component_access(&*self.world)); + )* + } + + fn archetype_component_access(&self) -> Access { + let (#(#param,)*) = &self.0; + let mut combined_access = Access::::default(); + #({ + combined_access.extend(&#param.archetype_component_access()); + })*; + combined_access + } + + fn component_access_set(&self) -> FilteredAccessSet { + let (#(#param,)*) = &self.0; + let mut combined_access = FilteredAccessSet::::default(); + #({ + combined_access.extend(#param.component_access_set()); + })*; + combined_access + } + + fn default_config() -> Self::Config { + (#(#param_fetch::default_config(),)*) + } + } + + + + impl<'w, 's, #(#param_fetch: for<'w1, 's1> SystemParamFetch<'w1, 's1>,)*> SystemParamFetch<'w, 's> for ParamSetState<(#(#param_fetch,)*)> + { + type Item = ParamSet<'w, 's, (#(<#param_fetch as SystemParamFetch<'w, 's>>::Item,)*)>; + + #[inline] + unsafe fn get_param( + state: &'s mut Self, + system_meta: &SystemMeta, + world: &'w World, + change_tick: u32, + ) -> Self::Item { + ParamSet { + param_states: &mut state.0, + system_meta: system_meta.clone(), + world, + change_tick, + } + } + } + + impl<'w, 's, #(#param: SystemParam,)*> ParamSet<'w, 's, (#(#param,)*)> + { + + #(#param_fn_mut)* + } + })); + } + + tokens +} #[derive(Default)] struct SystemParamFieldAttributes { diff --git a/crates/bevy_ecs/src/query/access.rs b/crates/bevy_ecs/src/query/access.rs index 867c71ea4d851..2653091397231 100644 --- a/crates/bevy_ecs/src/query/access.rs +++ b/crates/bevy_ecs/src/query/access.rs @@ -195,7 +195,7 @@ impl FilteredAccess { self.without.union_with(&access.without); } } - +#[derive(Clone)] pub struct FilteredAccessSet { combined_access: Access, filtered_accesses: Vec>, diff --git a/crates/bevy_ecs/src/system/function_system.rs b/crates/bevy_ecs/src/system/function_system.rs index 15f5b8a952563..0194fca93c9e5 100644 --- a/crates/bevy_ecs/src/system/function_system.rs +++ b/crates/bevy_ecs/src/system/function_system.rs @@ -12,6 +12,7 @@ use bevy_ecs_macros::all_tuples; use std::{borrow::Cow, marker::PhantomData}; /// The metadata of a [`System`]. +#[derive(Clone)] pub struct SystemMeta { pub(crate) name: Cow<'static, str>, pub(crate) component_access_set: FilteredAccessSet, diff --git a/crates/bevy_ecs/src/system/system_param.rs b/crates/bevy_ecs/src/system/system_param.rs index 6092a96ea1c00..d1dc8b0721906 100644 --- a/crates/bevy_ecs/src/system/system_param.rs +++ b/crates/bevy_ecs/src/system/system_param.rs @@ -13,7 +13,7 @@ use crate::{ world::{FromWorld, World}, }; pub use bevy_ecs_macros::SystemParam; -use bevy_ecs_macros::{all_tuples, impl_query_set}; +use bevy_ecs_macros::{all_tuples, impl_param_set, impl_query_set}; use std::{ fmt::Debug, marker::PhantomData, @@ -216,6 +216,16 @@ impl_query_set!(); pub trait Resource: Send + Sync + 'static {} impl Resource for T where T: Send + Sync + 'static {} +pub struct ParamSet<'w, 's, T: SystemParam> { + param_states: &'s mut T::Fetch, + world: &'w World, + system_meta: SystemMeta, + change_tick: u32, +} + +pub struct ParamSetState(T); + +impl_param_set!(); /// Shared borrow of a resource. /// From aeffdad65cc6d752d07eb4ba862ea27322ea1e7c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=8Fvar=20K=C3=A4llstr=C3=B6m?= Date: Thu, 2 Sep 2021 14:15:04 +0200 Subject: [PATCH 06/34] add some tests --- crates/bevy_ecs/src/system/mod.rs | 250 +++++++++++++++++++++++++++++- 1 file changed, 248 insertions(+), 2 deletions(-) diff --git a/crates/bevy_ecs/src/system/mod.rs b/crates/bevy_ecs/src/system/mod.rs index e17a9f78e0b61..2962ec0f059ba 100644 --- a/crates/bevy_ecs/src/system/mod.rs +++ b/crates/bevy_ecs/src/system/mod.rs @@ -95,8 +95,8 @@ mod tests { query::{Added, Changed, Or, QueryState, With, Without}, schedule::{Schedule, Stage, SystemStage}, system::{ - ConfigurableSystem, IntoExclusiveSystem, IntoSystem, Local, NonSend, NonSendMut, Query, - QuerySet, RemovedComponents, Res, ResMut, System, SystemState, + ConfigurableSystem, IntoExclusiveSystem, IntoSystem, Local, NonSend, NonSendMut, + ParamSet, Query, QuerySet, RemovedComponents, Res, ResMut, System, SystemState, }, world::{FromWorld, World}, }; @@ -230,6 +230,34 @@ mod tests { assert!(*world.get_resource::().unwrap(), "system ran"); } + #[test] + fn or_param_set_system() { + // Regression test for issue #762 + fn param_system( + mut ran: ResMut, + mut set: ParamSet<( + Query<(), Or<(Changed, Changed)>>, + Query<(), Or<(Added, Added)>>, + )>, + ) { + let changed = set.p0().iter().count(); + let added = set.p1().iter().count(); + + assert_eq!(changed, 1); + assert_eq!(added, 1); + + *ran = true; + } + + let mut world = World::default(); + world.insert_resource(false); + world.spawn().insert_bundle((A, B)); + + run_system(&mut world, param_system); + + assert!(*world.get_resource::().unwrap(), "system ran"); + } + #[test] fn changed_resource_system() { struct Added(usize); @@ -317,6 +345,13 @@ mod tests { run_system(&mut world, sys); } + #[test] + fn param_set_system() { + fn sys(mut _set: ParamSet<(Query<&mut A>, Query<&A>)>) {} + let mut world = World::default(); + run_system(&mut world, sys); + } + #[test] #[should_panic] fn conflicting_query_with_query_set_system() { @@ -326,6 +361,15 @@ mod tests { run_system(&mut world, sys); } + #[test] + #[should_panic] + fn conflicting_query_with_param_set_system() { + fn sys(_query: Query<&mut A>, _set: ParamSet<(Query<&mut A>, Query<&B>)>) {} + + let mut world = World::default(); + run_system(&mut world, sys); + } + #[test] #[should_panic] fn conflicting_query_sets_system() { @@ -339,6 +383,15 @@ mod tests { run_system(&mut world, sys); } + #[test] + #[should_panic] + fn conflicting_param_sets_system() { + fn sys(_set_1: ParamSet<(Query<&mut A>,)>, _set_2: ParamSet<(Query<&mut A>, Query<&B>)>) {} + + let mut world = World::default(); + run_system(&mut world, sys); + } + #[derive(Default)] struct BufferRes { _buffer: Vec, @@ -811,3 +864,196 @@ mod tests { } } } +/// ```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 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_param_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::*; +/// struct A(usize); +/// fn query_set(mut queries: ParamSet<(Query<&mut A>, Query<&A>)>, e: Res) { +/// let q1 = queries.p1(); +/// let a = q1.get(*e).unwrap(); +/// +/// let mut q2 = queries.p0(); +/// let mut b = q2.get_mut(*e).unwrap(); +/// // this should fail to compile +/// b.0 = a.0 +/// } +/// ``` +#[allow(unused)] +#[cfg(doc)] +fn system_param_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() {} From 142b123a880e4d317264d6754c36449d82941ce7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=8Fvar=20K=C3=A4llstr=C3=B6m?= Date: Thu, 2 Sep 2021 14:18:51 +0200 Subject: [PATCH 07/34] add safety comments --- crates/bevy_ecs/macros/src/lib.rs | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/crates/bevy_ecs/macros/src/lib.rs b/crates/bevy_ecs/macros/src/lib.rs index 9b3779fc116d3..dc394ab1a4801 100644 --- a/crates/bevy_ecs/macros/src/lib.rs +++ b/crates/bevy_ecs/macros/src/lib.rs @@ -323,7 +323,7 @@ pub fn impl_param_set(_input: TokenStream) -> TokenStream { param_fn_muts.push(quote! { pub fn #fn_name<'a>(&'a mut self) -> <#param::Fetch as SystemParamFetch<'a, 'a>>::Item { // SAFE: systems run without conflicts with other systems. - // Conflicting queries in ParamSet are not accessible at the same time + // Conflicting params in ParamSet are not accessible at the same time // ParamSets are guaranteed to not conflict with other SystemParams unsafe { <#param::Fetch as SystemParamFetch<'a, 'a>>::get_param(&mut self.param_states.#index, &self.system_meta, self.world, self.change_tick) @@ -343,13 +343,13 @@ pub fn impl_param_set(_input: TokenStream) -> TokenStream { type Fetch = ParamSetState<(#(#param::Fetch,)*)>; } - // SAFE: All Queries are constrained to ReadOnlyFetch, so World is only read + // SAFE: All parameters are constrained to ReadOnlyFetch, so World is only read unsafe impl<#(#param_fetch: for<'w1, 's1> SystemParamFetch<'w1, 's1>,)*> ReadOnlySystemParamFetch for ParamSetState<(#(#param_fetch,)*)> where #(#param_fetch: ReadOnlySystemParamFetch,)* { } - // SAFE: Relevant query ComponentId and ArchetypeComponentId access is applied to SystemMeta. If any QueryState conflicts + // SAFE: Relevant parameter ComponentId and ArchetypeComponentId access is applied to SystemMeta. If any ParamState conflicts // with any prior access, a panic will occur. unsafe impl<#(#param_fetch: for<'w1, 's1> SystemParamFetch<'w1, 's1>,)*> SystemParamState for ParamSetState<(#(#param_fetch,)*)> @@ -378,9 +378,6 @@ pub fn impl_param_set(_input: TokenStream) -> TokenStream { let (#(#param,)*) = &mut self.0; #( #param.new_archetype(archetype, system_meta); - // system_meta - // .archetype_component_access - // .extend(&#param.archetype_component_access(&*self.world)); )* } From 33ac800dcea14d5032dde34fc583bdc9aed78fb9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=8Fvar=20K=C3=A4llstr=C3=B6m?= Date: Thu, 2 Sep 2021 15:11:15 +0200 Subject: [PATCH 08/34] fix access bug --- crates/bevy_ecs/src/query/access.rs | 21 ++++++++++----------- 1 file changed, 10 insertions(+), 11 deletions(-) diff --git a/crates/bevy_ecs/src/query/access.rs b/crates/bevy_ecs/src/query/access.rs index 2653091397231..1c31906ecdc2a 100644 --- a/crates/bevy_ecs/src/query/access.rs +++ b/crates/bevy_ecs/src/query/access.rs @@ -129,7 +129,7 @@ impl Access { } } -#[derive(Clone, Eq, PartialEq)] +#[derive(Clone, Eq, PartialEq, Debug)] pub struct FilteredAccess { access: Access, with: FixedBitSet, @@ -195,7 +195,7 @@ impl FilteredAccess { self.without.union_with(&access.without); } } -#[derive(Clone)] +#[derive(Clone, Debug)] pub struct FilteredAccessSet { combined_access: Access, filtered_accesses: Vec>, @@ -216,12 +216,12 @@ impl FilteredAccessSet { // if combined unfiltered access is incompatible, check each filtered access for // compatibility let mut conflicts = HashSet::::default(); + println!("hashset size {}", conflicts.len()); if !filtered_access.access.is_compatible(&self.combined_access) { for current_filtered_access in self.filtered_accesses.iter() { if !current_filtered_access.is_compatible(filtered_access) { conflicts.extend( - current_filtered_access - .access + current_filtered_access.access .get_conflicts(&filtered_access.access) .iter() .map(|ind| ind.sparse_set_index()), @@ -229,6 +229,7 @@ impl FilteredAccessSet { } } } + println!("hashset size {}", conflicts.len()); conflicts .iter() .map(|ind| T::get_sparse_set_index(*ind)) @@ -244,13 +245,11 @@ impl FilteredAccessSet { .is_compatible(&self.combined_access) { for current_filtered_access in filtered_access_set.filtered_accesses.iter() { - if !current_filtered_access.is_compatible(current_filtered_access) { - conflicts.extend( - self.get_conflicts(¤t_filtered_access) - .iter() - .map(|ind| ind.sparse_set_index()), - ); - } + conflicts.extend( + self.get_conflicts(¤t_filtered_access) + .iter() + .map(|ind| ind.sparse_set_index()), + ); } } conflicts From 089b904cd4ce6383b06a468724f28f0519e94b61 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=8Fvar=20K=C3=A4llstr=C3=B6m?= Date: Thu, 2 Sep 2021 15:17:55 +0200 Subject: [PATCH 09/34] run cargo fmt --- crates/bevy_ecs/src/query/access.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/crates/bevy_ecs/src/query/access.rs b/crates/bevy_ecs/src/query/access.rs index 1c31906ecdc2a..2528e053ca874 100644 --- a/crates/bevy_ecs/src/query/access.rs +++ b/crates/bevy_ecs/src/query/access.rs @@ -221,7 +221,8 @@ impl FilteredAccessSet { for current_filtered_access in self.filtered_accesses.iter() { if !current_filtered_access.is_compatible(filtered_access) { conflicts.extend( - current_filtered_access.access + current_filtered_access + .access .get_conflicts(&filtered_access.access) .iter() .map(|ind| ind.sparse_set_index()), From 907b02d2599e226d9554ecef33429d0b5e4879b4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=8Fvar=20K=C3=A4llstr=C3=B6m?= Date: Thu, 2 Sep 2021 15:23:27 +0200 Subject: [PATCH 10/34] fix clippy stuff --- crates/bevy_ecs/macros/src/lib.rs | 3 +-- crates/bevy_ecs/src/query/access.rs | 8 ++++---- crates/bevy_ecs/src/system/system_param.rs | 10 +++++----- 3 files changed, 10 insertions(+), 11 deletions(-) diff --git a/crates/bevy_ecs/macros/src/lib.rs b/crates/bevy_ecs/macros/src/lib.rs index dc394ab1a4801..1896b8b4cf02b 100644 --- a/crates/bevy_ecs/macros/src/lib.rs +++ b/crates/bevy_ecs/macros/src/lib.rs @@ -316,8 +316,7 @@ pub fn impl_param_set(_input: TokenStream) -> TokenStream { let params_fetch = get_idents(|i| format!("PF{}", i), max_params); let values = get_idents(|i| format!("p{}", i), max_params); let mut param_fn_muts = Vec::new(); - for i in 0..max_params { - let param = ¶ms[i]; + for (i, param) in params.iter().enumerate() { let fn_name = Ident::new(&format!("p{}", i), Span::call_site()); let index = Index::from(i); param_fn_muts.push(quote! { diff --git a/crates/bevy_ecs/src/query/access.rs b/crates/bevy_ecs/src/query/access.rs index 2528e053ca874..5afc3c9a5d41b 100644 --- a/crates/bevy_ecs/src/query/access.rs +++ b/crates/bevy_ecs/src/query/access.rs @@ -146,10 +146,10 @@ impl Default for FilteredAccess { } } -impl Into> for FilteredAccess { - fn into(self) -> FilteredAccessSet { +impl From> for FilteredAccessSet { + fn from(filtered_access: FilteredAccess) -> Self { let mut base = FilteredAccessSet::::default(); - base.add(self); + base.add(filtered_access); base } } @@ -247,7 +247,7 @@ impl FilteredAccessSet { { for current_filtered_access in filtered_access_set.filtered_accesses.iter() { conflicts.extend( - self.get_conflicts(¤t_filtered_access) + self.get_conflicts(current_filtered_access) .iter() .map(|ind| ind.sparse_set_index()), ); diff --git a/crates/bevy_ecs/src/system/system_param.rs b/crates/bevy_ecs/src/system/system_param.rs index d1dc8b0721906..240b74f1b8d44 100644 --- a/crates/bevy_ecs/src/system/system_param.rs +++ b/crates/bevy_ecs/src/system/system_param.rs @@ -131,7 +131,7 @@ where fn init(world: &mut World, system_meta: &mut SystemMeta, _config: Self::Config) -> Self { let state = QueryState::new(world); assert_component_access_compatibility( - &system_meta, + system_meta, std::any::type_name::>(), &state, world, @@ -328,7 +328,7 @@ unsafe impl SystemParamState for ResState { marker: PhantomData, }; assert_component_access_compatibility( - &system_meta, + system_meta, std::any::type_name::>(), &state, world, @@ -476,7 +476,7 @@ unsafe impl SystemParamState for ResMutState { marker: PhantomData, }; assert_component_access_compatibility( - &system_meta, + system_meta, std::any::type_name::>(), &state, world, @@ -906,7 +906,7 @@ unsafe impl SystemParamState for NonSendState { }; assert_component_access_compatibility( - &system_meta, + system_meta, std::any::type_name::>(), &state, world, @@ -1059,7 +1059,7 @@ unsafe impl SystemParamState for NonSendMutState { }; assert_component_access_compatibility( - &system_meta, + system_meta, std::any::type_name::>(), &state, world, From 5955bfe83abc924585562671e924ab4ed49ed672 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=8Fvar=20K=C3=A4llstr=C3=B6m?= Date: Thu, 2 Sep 2021 16:09:54 +0200 Subject: [PATCH 11/34] add specialized panic messages --- crates/bevy_ecs/macros/src/lib.rs | 1 + crates/bevy_ecs/src/system/system_param.rs | 11 +++++++++++ 2 files changed, 12 insertions(+) diff --git a/crates/bevy_ecs/macros/src/lib.rs b/crates/bevy_ecs/macros/src/lib.rs index 1896b8b4cf02b..8a9002d705172 100644 --- a/crates/bevy_ecs/macros/src/lib.rs +++ b/crates/bevy_ecs/macros/src/lib.rs @@ -233,6 +233,7 @@ pub fn impl_query_set(_input: TokenStream) -> TokenStream { std::any::type_name::>(), &#query, world, + ParamConflictType::Query, ); )* #( diff --git a/crates/bevy_ecs/src/system/system_param.rs b/crates/bevy_ecs/src/system/system_param.rs index 240b74f1b8d44..67a586cbda7e8 100644 --- a/crates/bevy_ecs/src/system/system_param.rs +++ b/crates/bevy_ecs/src/system/system_param.rs @@ -135,6 +135,7 @@ where std::any::type_name::>(), &state, world, + ParamConflictType::Query, ); system_meta .component_access_set @@ -181,11 +182,17 @@ where } } +pub enum ParamConflictType { + Query, + Resource, + Default, +} fn assert_component_access_compatibility( system_meta: &SystemMeta, param_type: &'static str, state: &impl SystemParamState, world: &World, + conflict_type: ParamConflictType, ) { let system_name = &system_meta.name; let mut conflicts = system_meta @@ -332,6 +339,7 @@ unsafe impl SystemParamState for ResState { std::any::type_name::>(), &state, world, + ParamConflictType::Resource, ); system_meta .component_access_set @@ -480,6 +488,7 @@ unsafe impl SystemParamState for ResMutState { std::any::type_name::>(), &state, world, + ParamConflictType::Resource, ); system_meta .component_access_set @@ -910,6 +919,7 @@ unsafe impl SystemParamState for NonSendState { std::any::type_name::>(), &state, world, + ParamConflictType::Resource, ); system_meta .component_access_set @@ -1063,6 +1073,7 @@ unsafe impl SystemParamState for NonSendMutState { std::any::type_name::>(), &state, world, + ParamConflictType::Resource, ); system_meta .component_access_set From 3f9056a86d55c9d782695563bb2b5a9b0f4ec2ba Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=8Fvar=20K=C3=A4llstr=C3=B6m?= Date: Thu, 2 Sep 2021 16:50:49 +0200 Subject: [PATCH 12/34] remove debug comments --- crates/bevy_ecs/src/query/access.rs | 2 -- 1 file changed, 2 deletions(-) diff --git a/crates/bevy_ecs/src/query/access.rs b/crates/bevy_ecs/src/query/access.rs index 5afc3c9a5d41b..e981b046d2ab8 100644 --- a/crates/bevy_ecs/src/query/access.rs +++ b/crates/bevy_ecs/src/query/access.rs @@ -216,7 +216,6 @@ impl FilteredAccessSet { // if combined unfiltered access is incompatible, check each filtered access for // compatibility let mut conflicts = HashSet::::default(); - println!("hashset size {}", conflicts.len()); if !filtered_access.access.is_compatible(&self.combined_access) { for current_filtered_access in self.filtered_accesses.iter() { if !current_filtered_access.is_compatible(filtered_access) { @@ -230,7 +229,6 @@ impl FilteredAccessSet { } } } - println!("hashset size {}", conflicts.len()); conflicts .iter() .map(|ind| T::get_sparse_set_index(*ind)) From 3b77ea33042debabbd3fefcc148b9f7fe557cfa2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=8Fvar=20K=C3=A4llstr=C3=B6m?= Date: Thu, 2 Sep 2021 22:33:59 +0200 Subject: [PATCH 13/34] add ParamSet to prelude --- crates/bevy_ecs/src/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crates/bevy_ecs/src/lib.rs b/crates/bevy_ecs/src/lib.rs index 6020a9d68ecb7..69dc461dd50a5 100644 --- a/crates/bevy_ecs/src/lib.rs +++ b/crates/bevy_ecs/src/lib.rs @@ -32,7 +32,7 @@ pub mod prelude { }, system::{ Commands, ConfigurableSystem, In, IntoChainSystem, IntoExclusiveSystem, IntoSystem, - Local, NonSend, NonSendMut, Query, QuerySet, RemovedComponents, Res, ResMut, System, + Local, NonSend, NonSendMut, Query, QuerySet, ParamSet, RemovedComponents, Res, ResMut, System, }, world::{FromWorld, Mut, World}, }; From d678368b368f24c55ab9be416c928cf00c6d9272 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=8Fvar=20K=C3=A4llstr=C3=B6m?= Date: Thu, 2 Sep 2021 23:05:25 +0200 Subject: [PATCH 14/34] added paramset to prelude --- crates/bevy_ecs/src/lib.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/crates/bevy_ecs/src/lib.rs b/crates/bevy_ecs/src/lib.rs index 69dc461dd50a5..c512347b7dfb1 100644 --- a/crates/bevy_ecs/src/lib.rs +++ b/crates/bevy_ecs/src/lib.rs @@ -32,7 +32,8 @@ pub mod prelude { }, system::{ Commands, ConfigurableSystem, In, IntoChainSystem, IntoExclusiveSystem, IntoSystem, - Local, NonSend, NonSendMut, Query, QuerySet, ParamSet, RemovedComponents, Res, ResMut, System, + Local, NonSend, NonSendMut, ParamSet, Query, QuerySet, RemovedComponents, Res, ResMut, + System, }, world::{FromWorld, Mut, World}, }; From bc72f561a9a12b08fbad3df594c7ca2083df8d60 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=8Fvar=20K=C3=A4llstr=C3=B6m?= Date: Thu, 2 Sep 2021 23:08:19 +0200 Subject: [PATCH 15/34] add docstrings --- crates/bevy_ecs/src/system/system_param.rs | 34 ++++++++++++++++++++-- 1 file changed, 32 insertions(+), 2 deletions(-) diff --git a/crates/bevy_ecs/src/system/system_param.rs b/crates/bevy_ecs/src/system/system_param.rs index 67a586cbda7e8..397b982929dd2 100644 --- a/crates/bevy_ecs/src/system/system_param.rs +++ b/crates/bevy_ecs/src/system/system_param.rs @@ -223,14 +223,44 @@ impl_query_set!(); pub trait Resource: Send + Sync + 'static {} impl Resource for T where T: Send + Sync + 'static {} +/// A set of possibly conflicting [`SystemParam`]s which can be accessed one at a time. +/// +/// The type parameter of a [`ParamSet`] is a tuple of up to 4 [`SystemParam`]s +/// These can be acquired _one at a time_ by calling `param_set.p0()`, `param_set.p1()`, etc. +/// # Examples +/// +/// ``` +/// # use bevy_ecs::prelude::*; +/// # let world = &mut World::default(); +/// struct A(usize); +/// struct B(usize); +/// fn write_to_both( +/// mut param_set: ParamSet<(Query<&mut A>, Query<(&A, &mut B)>)> // These Queries are conflicting +/// ) { +/// let mut q0 = param_set.p0(); +/// // let q1 = param_set.p1(); <-- This won't compile since q0 is in scope +/// for mut a in q0.iter_mut() { +/// a.0 = 42; +/// } +/// // Now q0 is out of scope, the second query can be retrieved +/// let mut q1 = param_set.p1(); +/// for (a, mut b) in q1.iter_mut() { +/// b.0 = a.0; +/// } +/// } +/// +/// let mut write_to_both_system = write_to_both.system(); +/// write_to_both_system.initialize(world); +/// write_to_both_system.run((), world); +/// ``` pub struct ParamSet<'w, 's, T: SystemParam> { param_states: &'s mut T::Fetch, world: &'w World, system_meta: SystemMeta, change_tick: u32, } - -pub struct ParamSetState(T); +/// The [`SystemParamState`] of [`ParamSet`]. +pub struct ParamSetState SystemParamFetch<'w, 's>>(T); impl_param_set!(); From 90a52369b14bb8efd306343d904ae3ef4c6448b5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=8Fvar=20K=C3=A4llstr=C3=B6m?= Date: Thu, 2 Sep 2021 23:13:45 +0200 Subject: [PATCH 16/34] remove ParamConflictType --- crates/bevy_ecs/macros/src/lib.rs | 2 +- crates/bevy_ecs/src/system/system_param.rs | 17 ++++++----------- 2 files changed, 7 insertions(+), 12 deletions(-) diff --git a/crates/bevy_ecs/macros/src/lib.rs b/crates/bevy_ecs/macros/src/lib.rs index 8a9002d705172..1e95284787782 100644 --- a/crates/bevy_ecs/macros/src/lib.rs +++ b/crates/bevy_ecs/macros/src/lib.rs @@ -233,7 +233,7 @@ pub fn impl_query_set(_input: TokenStream) -> TokenStream { std::any::type_name::>(), &#query, world, - ParamConflictType::Query, + true, ); )* #( diff --git a/crates/bevy_ecs/src/system/system_param.rs b/crates/bevy_ecs/src/system/system_param.rs index 397b982929dd2..d87e5446b3cd2 100644 --- a/crates/bevy_ecs/src/system/system_param.rs +++ b/crates/bevy_ecs/src/system/system_param.rs @@ -135,7 +135,7 @@ where std::any::type_name::>(), &state, world, - ParamConflictType::Query, + true, ); system_meta .component_access_set @@ -182,17 +182,12 @@ where } } -pub enum ParamConflictType { - Query, - Resource, - Default, -} fn assert_component_access_compatibility( system_meta: &SystemMeta, param_type: &'static str, state: &impl SystemParamState, world: &World, - conflict_type: ParamConflictType, + is_query: bool, ) { let system_name = &system_meta.name; let mut conflicts = system_meta @@ -369,7 +364,7 @@ unsafe impl SystemParamState for ResState { std::any::type_name::>(), &state, world, - ParamConflictType::Resource, + false, ); system_meta .component_access_set @@ -518,7 +513,7 @@ unsafe impl SystemParamState for ResMutState { std::any::type_name::>(), &state, world, - ParamConflictType::Resource, + false, ); system_meta .component_access_set @@ -949,7 +944,7 @@ unsafe impl SystemParamState for NonSendState { std::any::type_name::>(), &state, world, - ParamConflictType::Resource, + false, ); system_meta .component_access_set @@ -1103,7 +1098,7 @@ unsafe impl SystemParamState for NonSendMutState { std::any::type_name::>(), &state, world, - ParamConflictType::Resource, + false, ); system_meta .component_access_set From dae0456724ea40c717f4193de5fd54fc713cd5dc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=8Fvar=20K=C3=A4llstr=C3=B6m?= Date: Fri, 3 Sep 2021 10:39:44 +0200 Subject: [PATCH 17/34] remove QuerySet in favour of ParamSet --- crates/bevy_ecs/macros/src/lib.rs | 130 -------------------- crates/bevy_ecs/src/lib.rs | 3 +- crates/bevy_ecs/src/system/mod.rs | 131 +++------------------ crates/bevy_ecs/src/system/system_param.rs | 2 +- crates/bevy_render/src/camera/camera.rs | 14 +-- crates/bevy_render/src/mesh/mesh/mod.rs | 8 ++ crates/bevy_text/src/text2d.rs | 14 +-- crates/bevy_ui/src/widget/text.rs | 19 ++- examples/game/alien_cake_addict.rs | 13 +- 9 files changed, 56 insertions(+), 278 deletions(-) diff --git a/crates/bevy_ecs/macros/src/lib.rs b/crates/bevy_ecs/macros/src/lib.rs index 1e95284787782..9bd94a9c3b5a2 100644 --- a/crates/bevy_ecs/macros/src/lib.rs +++ b/crates/bevy_ecs/macros/src/lib.rs @@ -179,136 +179,6 @@ fn get_idents(fmt_string: fn(usize) -> String, count: usize) -> Vec { .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 mut query_fn_muts = Vec::new(); - for i in 0..max_queries { - let query = &queries[i]; - let filter = &filters[i]; - let fn_name = Ident::new(&format!("q{}", i), Span::call_site()); - let index = Index::from(i); - query_fn_muts.push(quote! { - 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) - } - } - }); - } - - for query_count in 1..=max_queries { - let query = &queries[0..query_count]; - let filter = &filters[0..query_count]; - let query_fn_mut = &query_fn_muts[0..query_count]; - tokens.extend(TokenStream::from(quote! { - 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>,)*)>; - } - - // SAFE: All Queries are constrained to ReadOnlyFetch, so World is only read - unsafe impl<#(#query: WorldQuery + 'static,)* #(#filter: WorldQuery + 'static,)*> ReadOnlySystemParamFetch for QuerySetState<(#(QueryState<#query, #filter>,)*)> - where #(#query::Fetch: ReadOnlyFetch,)* #(#filter::Fetch: FilterFetch,)* - { } - - // SAFE: Relevant query ComponentId and ArchetypeComponentId access is applied to SystemMeta. If any QueryState conflicts - // with any prior access, a panic will occur. - unsafe impl<#(#query: WorldQuery + 'static,)* #(#filter: WorldQuery + 'static,)*> SystemParamState for QuerySetState<(#(QueryState<#query, #filter>,)*)> - where #(#filter::Fetch: FilterFetch,)* - { - type Config = (); - fn init(world: &mut World, system_meta: &mut SystemMeta, config: Self::Config) -> Self { - #( - let mut #query = QueryState::<#query, #filter>::new(world); - assert_component_access_compatibility( - &system_meta, - std::any::type_name::>(), - &#query, - world, - true, - ); - )* - #( - system_meta - .component_access_set - .add(#query.component_access.clone()); - system_meta - .archetype_component_access - .extend(&#query.archetype_component_access); - )* - QuerySetState((#(#query,)*)) - } - - fn archetype_component_access(&self) -> Access { - let (#(#query,)*) = &self.0; - let mut combined_access = Access::::default(); - #({ - combined_access.extend(&#query.archetype_component_access()); - })*; - combined_access - } - - fn component_access_set(&self) -> FilteredAccessSet { - let (#(#query,)*) = &self.0; - let mut combined_access = FilteredAccessSet::::default(); - #({ - combined_access.extend(#query.component_access_set()); - })*; - combined_access - } - - fn new_archetype(&mut self, archetype: &Archetype, system_meta: &mut SystemMeta) { - let (#(#query,)*) = &mut self.0; - #( - #query.new_archetype(archetype); - system_meta - .archetype_component_access - .extend(&#query.archetype_component_access); - )* - } - - fn default_config() {} - } - - impl<'w, 's, #(#query: WorldQuery + 'static,)* #(#filter: WorldQuery + 'static,)*> SystemParamFetch<'w, 's> for QuerySetState<(#(QueryState<#query, #filter>,)*)> - where #(#filter::Fetch: FilterFetch,)* - { - type Item = QuerySet<'w, 's, (#(QueryState<#query, #filter>,)*)>; - - #[inline] - unsafe fn get_param( - state: &'s mut Self, - system_meta: &SystemMeta, - world: &'w World, - change_tick: u32, - ) -> Self::Item { - QuerySet { - query_states: &state.0, - world, - last_change_tick: system_meta.last_change_tick, - change_tick, - } - } - } - - impl<'w, 's, #(#query: WorldQuery,)* #(#filter: WorldQuery,)*> QuerySet<'w, 's, (#(QueryState<#query, #filter>,)*)> - where #(#filter::Fetch: FilterFetch,)* - { - #(#query_fn_mut)* - } - })); - } - - tokens -} #[proc_macro] pub fn impl_param_set(_input: TokenStream) -> TokenStream { let mut tokens = TokenStream::new(); diff --git a/crates/bevy_ecs/src/lib.rs b/crates/bevy_ecs/src/lib.rs index c512347b7dfb1..d5fa1e5b96a13 100644 --- a/crates/bevy_ecs/src/lib.rs +++ b/crates/bevy_ecs/src/lib.rs @@ -32,8 +32,7 @@ pub mod prelude { }, system::{ Commands, ConfigurableSystem, In, IntoChainSystem, IntoExclusiveSystem, IntoSystem, - Local, NonSend, NonSendMut, ParamSet, Query, QuerySet, RemovedComponents, Res, ResMut, - System, + Local, NonSend, NonSendMut, ParamSet, Query, RemovedComponents, Res, ResMut, System, }, world::{FromWorld, Mut, World}, }; diff --git a/crates/bevy_ecs/src/system/mod.rs b/crates/bevy_ecs/src/system/mod.rs index 2962ec0f059ba..e90430050785b 100644 --- a/crates/bevy_ecs/src/system/mod.rs +++ b/crates/bevy_ecs/src/system/mod.rs @@ -92,11 +92,11 @@ mod tests { bundle::Bundles, component::{Component, Components}, entity::{Entities, Entity}, - query::{Added, Changed, Or, QueryState, With, Without}, + query::{Added, Changed, Or, With, Without}, schedule::{Schedule, Stage, SystemStage}, system::{ ConfigurableSystem, IntoExclusiveSystem, IntoSystem, Local, NonSend, NonSendMut, - ParamSet, Query, QuerySet, RemovedComponents, Res, ResMut, System, SystemState, + ParamSet, Query, RemovedComponents, Res, ResMut, System, SystemState, }, world::{FromWorld, World}, }; @@ -202,38 +202,10 @@ mod tests { assert!(*world.get_resource::().unwrap(), "system ran"); } - #[test] - fn or_query_set_system() { - // Regression test for issue #762 - fn query_system( - mut ran: ResMut, - mut set: QuerySet<( - QueryState<(), Or<(Changed, Changed)>>, - QueryState<(), Or<(Added, Added)>>, - )>, - ) { - let changed = set.q0().iter().count(); - let added = set.q1().iter().count(); - - assert_eq!(changed, 1); - assert_eq!(added, 1); - - *ran = true; - } - - let mut world = World::default(); - world.insert_resource(false); - world.spawn().insert_bundle((A, B)); - - run_system(&mut world, query_system); - - assert!(*world.get_resource::().unwrap(), "system ran"); - } - #[test] fn or_param_set_system() { // Regression test for issue #762 - fn param_system( + fn query_system( mut ran: ResMut, mut set: ParamSet<( Query<(), Or<(Changed, Changed)>>, @@ -253,7 +225,7 @@ mod tests { world.insert_resource(false); world.spawn().insert_bundle((A, B)); - run_system(&mut world, param_system); + run_system(&mut world, query_system); assert!(*world.get_resource::().unwrap(), "system ran"); } @@ -338,13 +310,6 @@ mod tests { run_system(&mut world, sys); } - #[test] - fn query_set_system() { - fn sys(mut _set: QuerySet<(QueryState<&mut A>, QueryState<&A>)>) {} - let mut world = World::default(); - run_system(&mut world, sys); - } - #[test] fn param_set_system() { fn sys(mut _set: ParamSet<(Query<&mut A>, Query<&A>)>) {} @@ -352,15 +317,6 @@ mod tests { run_system(&mut world, sys); } - #[test] - #[should_panic] - fn conflicting_query_with_query_set_system() { - fn sys(_query: Query<&mut A>, _set: QuerySet<(QueryState<&mut A>, QueryState<&B>)>) {} - - let mut world = World::default(); - run_system(&mut world, sys); - } - #[test] #[should_panic] fn conflicting_query_with_param_set_system() { @@ -370,19 +326,6 @@ mod tests { run_system(&mut world, sys); } - #[test] - #[should_panic] - fn conflicting_query_sets_system() { - 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); - } - #[test] #[should_panic] fn conflicting_param_sets_system() { @@ -695,11 +638,8 @@ mod tests { world.insert_resource(A(42)); world.spawn().insert(B(7)); - let mut system_state: SystemState<( - Res, - Query<&B>, - QuerySet<(QueryState<&C>, QueryState<&D>)>, - )> = SystemState::new(&mut world); + let mut system_state: SystemState<(Res, Query<&B>, ParamSet<(Query<&C>, Query<&D>)>)> = + SystemState::new(&mut world); let (a, query, _) = system_state.get(&world); assert_eq!(*a, A(42), "returned resource matches initial value"); assert_eq!( @@ -899,12 +839,12 @@ 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(); +/// fn param_set(mut queries: ParamSet<(Query<&mut A>, Query<&A>)>, e: Res) { +/// let mut q2 = queries.p0(); /// let mut iter2 = q2.iter_mut(); /// let mut b = iter2.next().unwrap(); /// -/// let q1 = queries.q1(); +/// let q1 = queries.p1(); /// let mut iter = q1.iter(); /// let a = &*iter.next().unwrap(); /// @@ -914,17 +854,17 @@ fn system_query_get_lifetime_safety_test() {} /// ``` #[allow(unused)] #[cfg(doc)] -fn system_query_set_iter_lifetime_safety_test() {} +fn system_param_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(); +/// fn param_set(mut queries: ParamSet<(Query<&mut A>, Query<&A>)>, e: Res) { +/// let q1 = queries.p1(); /// let mut iter = q1.iter(); /// let a = &*iter.next().unwrap(); /// -/// let mut q2 = queries.q0(); +/// let mut q2 = queries.p0(); /// let mut iter2 = q2.iter_mut(); /// let mut b = iter2.next().unwrap(); /// @@ -934,34 +874,16 @@ fn system_query_set_iter_lifetime_safety_test() {} /// ``` #[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() {} +fn system_param_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(); +/// fn param_set(mut queries: ParamSet<(Query<&mut A>, Query<&A>)>, e: Res) { +/// let mut q2 = queries.p0(); /// let mut b = q2.get_mut(*e).unwrap(); /// -/// let q1 = queries.q1(); +/// let q1 = queries.p1(); /// let a = q1.get(*e).unwrap(); /// /// // this should fail to compile @@ -975,24 +897,7 @@ fn system_param_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::*; -/// struct A(usize); -/// fn query_set(mut queries: ParamSet<(Query<&mut A>, Query<&A>)>, e: Res) { +/// fn param_set(mut queries: ParamSet<(Query<&mut A>, Query<&A>)>, e: Res) { /// let q1 = queries.p1(); /// let a = q1.get(*e).unwrap(); /// diff --git a/crates/bevy_ecs/src/system/system_param.rs b/crates/bevy_ecs/src/system/system_param.rs index d87e5446b3cd2..73bf0554e79da 100644 --- a/crates/bevy_ecs/src/system/system_param.rs +++ b/crates/bevy_ecs/src/system/system_param.rs @@ -13,7 +13,7 @@ use crate::{ world::{FromWorld, World}, }; pub use bevy_ecs_macros::SystemParam; -use bevy_ecs_macros::{all_tuples, impl_param_set, impl_query_set}; +use bevy_ecs_macros::{all_tuples, impl_param_set}; use std::{ fmt::Debug, marker::PhantomData, diff --git a/crates/bevy_render/src/camera/camera.rs b/crates/bevy_render/src/camera/camera.rs index 4f73ebaf90230..2489b530abc60 100644 --- a/crates/bevy_render/src/camera/camera.rs +++ b/crates/bevy_render/src/camera/camera.rs @@ -3,10 +3,10 @@ use bevy_ecs::{ component::Component, entity::Entity, event::EventReader, - prelude::{DetectChanges, QueryState}, + prelude::Query, query::Added, reflect::ReflectComponent, - system::{QuerySet, Res}, + system::{ParamSet, Res}, }; use bevy_math::{Mat4, Vec2, Vec3}; use bevy_reflect::{Reflect, ReflectDeserialize}; @@ -75,9 +75,9 @@ pub fn camera_system( mut window_resized_events: EventReader, mut window_created_events: EventReader, windows: Res, - mut queries: QuerySet<( - QueryState<(Entity, &mut Camera, &mut T)>, - QueryState>, + mut queries: ParamSet<( + Query<(Entity, &mut Camera, &mut T)>, + Query>, )>, ) { let mut changed_window_ids = Vec::new(); @@ -102,10 +102,10 @@ pub fn camera_system( } let mut added_cameras = vec![]; - for entity in &mut queries.q1().iter() { + for entity in &mut queries.p1().iter() { added_cameras.push(entity); } - for (entity, mut camera, mut camera_projection) in queries.q0().iter_mut() { + for (entity, mut camera, mut camera_projection) in queries.p0().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/mesh/mesh/mod.rs b/crates/bevy_render/src/mesh/mesh/mod.rs index 1c82fdf1eed53..c908ba976bbe7 100644 --- a/crates/bevy_render/src/mesh/mesh/mod.rs +++ b/crates/bevy_render/src/mesh/mesh/mod.rs @@ -8,6 +8,14 @@ use crate::{ }; use bevy_core::cast_slice; use bevy_ecs::system::{lifetimeless::SRes, SystemParamItem}; +use bevy_ecs::{ + entity::Entity, + event::EventReader, + prelude::Query, + query::{Changed, With}, + system::{Local, ParamSet, Res}, + world::Mut, +}; use bevy_math::*; use bevy_reflect::TypeUuid; use bevy_utils::EnumVariantMeta; diff --git a/crates/bevy_text/src/text2d.rs b/crates/bevy_text/src/text2d.rs index f8cf94be449fa..beb6a17a27211 100644 --- a/crates/bevy_text/src/text2d.rs +++ b/crates/bevy_text/src/text2d.rs @@ -2,8 +2,8 @@ use bevy_asset::Assets; use bevy_ecs::{ bundle::Bundle, entity::Entity, - query::{Changed, QueryState, With}, - system::{Local, Query, QuerySet, Res, ResMut}, + query::{Changed, With, Without}, + system::{Local, ParamSet, Query, Res, ResMut}, }; use bevy_math::{Mat4, Size, Vec3}; use bevy_render::{texture::Image, RenderWorld}; @@ -117,13 +117,13 @@ pub fn text2d_system( mut texture_atlases: ResMut>, mut font_atlas_set_storage: ResMut>, mut text_pipeline: ResMut, - mut text_queries: QuerySet<( - QueryState, Changed)>, - QueryState<(&Text, &mut Text2dSize), With>, + mut text_queries: ParamSet<( + Query, Changed)>, + Query<(&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().iter_mut() { + for entity in text_queries.p0().iter_mut() { queued_text.entities.push(entity); } @@ -139,7 +139,7 @@ pub fn text2d_system( // Computes all text in the local queue let mut new_queue = Vec::new(); - let mut query = text_queries.q1(); + let mut query = text_queries.p1(); 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_ui/src/widget/text.rs b/crates/bevy_ui/src/widget/text.rs index 5af7a84c1d165..ab7efe11e2e73 100644 --- a/crates/bevy_ui/src/widget/text.rs +++ b/crates/bevy_ui/src/widget/text.rs @@ -2,9 +2,8 @@ use crate::{CalculatedSize, Style, Val}; use bevy_asset::Assets; use bevy_ecs::{ entity::Entity, - prelude::QueryState, - query::{Changed, Or, With}, - system::{Local, QuerySet, Res, ResMut}, + query::{Changed, Or, With, Without}, + system::{Local, ParamSet, Query, Res, ResMut}, }; use bevy_math::Size; use bevy_render::texture::Image; @@ -46,10 +45,10 @@ pub fn text_system( mut texture_atlases: ResMut>, mut font_atlas_set_storage: ResMut>, mut text_pipeline: ResMut, - mut text_queries: QuerySet<( - QueryState, Changed