diff --git a/crates/bevy_ecs/src/schedule/executor/mod.rs b/crates/bevy_ecs/src/schedule/executor/mod.rs index 710b88db6c23f..9e22de29f3f62 100644 --- a/crates/bevy_ecs/src/schedule/executor/mod.rs +++ b/crates/bevy_ecs/src/schedule/executor/mod.rs @@ -304,7 +304,7 @@ mod tests { use crate::{ prelude::{Component, In, IntoSystem, Resource, Schedule}, schedule::ExecutorKind, - system::{Populated, Res, ResMut, Single}, + system::{Populated, Res, ResMut, Single, When}, world::World, }; @@ -327,12 +327,12 @@ mod tests { #[derive(Resource, Default)] struct Counter(u8); - fn set_single_state(mut _single: Single<&TestComponent>, mut state: ResMut) { + fn set_single_state(mut _single: When>, mut state: ResMut) { state.single_ran = true; } fn set_populated_state( - mut _populated: Populated<&TestComponent>, + mut _populated: When>, mut state: ResMut, ) { state.populated_ran = true; @@ -404,7 +404,7 @@ mod tests { #[test] fn piped_systems_first_system_skipped() { // This system should be skipped when run due to no matching entity - fn pipe_out(_single: Single<&TestComponent>) -> u8 { + fn pipe_out(_single: When>) -> u8 { 42 } @@ -431,7 +431,7 @@ mod tests { } // This system should be skipped when run due to no matching entity - fn pipe_in(_input: In, _single: Single<&TestComponent>) {} + fn pipe_in(_input: In, _single: When>) {} let mut world = World::new(); world.init_resource::(); @@ -482,7 +482,7 @@ mod tests { #[test] fn piped_system_skip_and_panic() { // This system should be skipped when run due to no matching entity - fn pipe_out(_single: Single<&TestComponent>) -> u8 { + fn pipe_out(_single: When>) -> u8 { 42 } @@ -506,7 +506,7 @@ mod tests { } // This system should be skipped when run due to no matching entity - fn pipe_in(_input: In, _single: Single<&TestComponent>) {} + fn pipe_in(_input: In, _single: When>) {} let mut world = World::new(); let mut schedule = Schedule::default(); @@ -538,13 +538,17 @@ mod tests { fn piped_system_skip_and_skip() { // This system should be skipped when run due to no matching entity - fn pipe_out(_single: Single<&TestComponent>, mut counter: ResMut) -> u8 { + fn pipe_out(_single: When>, mut counter: ResMut) -> u8 { counter.0 += 1; 42 } // This system should be skipped when run due to no matching entity - fn pipe_in(_input: In, _single: Single<&TestComponent>, mut counter: ResMut) { + fn pipe_in( + _input: In, + _single: When>, + mut counter: ResMut, + ) { counter.0 += 1; } diff --git a/crates/bevy_ecs/src/system/query.rs b/crates/bevy_ecs/src/system/query.rs index dfc07d23f1bb0..31cbc40578a43 100644 --- a/crates/bevy_ecs/src/system/query.rs +++ b/crates/bevy_ecs/src/system/query.rs @@ -2566,9 +2566,11 @@ impl<'w, 'q, Q: QueryData, F: QueryFilter> From<&'q mut Query<'w, '_, Q, F>> /// [System parameter] that provides access to single entity's components, much like [`Query::single`]/[`Query::single_mut`]. /// /// This [`SystemParam`](crate::system::SystemParam) fails validation if zero or more than one matching entity exists. -/// This will cause the system to be skipped, according to the rules laid out in [`SystemParamValidationError`](crate::system::SystemParamValidationError). +/// This will cause the system to fail, according to the rules laid out in [`SystemParamValidationError`](crate::system::SystemParamValidationError). /// -/// Use [`Option>`] instead if zero or one matching entities can exist. +/// Use [`Option>`] instead to run the system but get `None` when there are zero or multiple matching entities. +/// +/// Use [`When>`](crate::system::When) instead to skip the system when there are zero or multiple matching entities. /// /// See [`Query`] for more details. /// @@ -2617,7 +2619,9 @@ impl<'w, D: QueryData, F: QueryFilter> Single<'w, D, F> { /// [System parameter] that works very much like [`Query`] except it always contains at least one matching entity. /// /// This [`SystemParam`](crate::system::SystemParam) fails validation if no matching entities exist. -/// This will cause the system to be skipped, according to the rules laid out in [`SystemParamValidationError`](crate::system::SystemParamValidationError). +/// This will cause the system to fail, according to the rules laid out in [`SystemParamValidationError`](crate::system::SystemParamValidationError). +/// +/// Use [`When>`](crate::system::When) instead to skip the system when there are zero matching entities. /// /// Much like [`Query::is_empty`] the worst case runtime will be `O(n)` where `n` is the number of *potential* matches. /// This can be notably expensive for queries that rely on non-archetypal filters such as [`Added`](crate::query::Added), diff --git a/crates/bevy_ecs/src/system/system_param.rs b/crates/bevy_ecs/src/system/system_param.rs index 8f36e6a8c28b9..93ad51aa156e9 100644 --- a/crates/bevy_ecs/src/system/system_param.rs +++ b/crates/bevy_ecs/src/system/system_param.rs @@ -441,10 +441,10 @@ unsafe impl<'a, D: QueryData + 'static, F: QueryFilter + 'static> SystemParam fo match query.single_inner() { Ok(_) => Ok(()), Err(QuerySingleError::NoEntities(_)) => Err( - SystemParamValidationError::skipped::("No matching entities"), + SystemParamValidationError::invalid::("No matching entities"), ), Err(QuerySingleError::MultipleEntities(_)) => Err( - SystemParamValidationError::skipped::("Multiple matching entities"), + SystemParamValidationError::invalid::("Multiple matching entities"), ), } } @@ -502,7 +502,7 @@ unsafe impl SystemParam state.query_unchecked_with_ticks(world, system_meta.last_run, world.change_tick()) }; if query.is_empty() { - Err(SystemParamValidationError::skipped::( + Err(SystemParamValidationError::invalid::( "No matching entities", )) } else { @@ -1827,6 +1827,8 @@ unsafe impl ReadOnlySystemParam for Result(message: impl Into>) -> Self { - Self::new::(true, message, Cow::Borrowed("")) - } - /// Constructs a `SystemParamValidationError` for an invalid parameter that should be treated as an error. /// The parameter name is initialized to the type name of `T`, so a `SystemParam` should usually pass `Self`. pub fn invalid(message: impl Into>) -> Self { diff --git a/crates/bevy_input_focus/src/lib.rs b/crates/bevy_input_focus/src/lib.rs index d146b1cc56264..9235ae56ff6b0 100644 --- a/crates/bevy_input_focus/src/lib.rs +++ b/crates/bevy_input_focus/src/lib.rs @@ -221,10 +221,10 @@ pub type InputFocusSet = InputFocusSystems; /// If no entity is focused, sets the focus to the primary window, if any. pub fn set_initial_focus( mut input_focus: ResMut, - window: Single>, + window: When>>, ) { if input_focus.0.is_none() { - input_focus.0 = Some(*window); + input_focus.0 = Some(**window); } } diff --git a/examples/ecs/fallible_params.rs b/examples/ecs/fallible_params.rs index 94a8007aec090..6a32e66c500b9 100644 --- a/examples/ecs/fallible_params.rs +++ b/examples/ecs/fallible_params.rs @@ -119,8 +119,8 @@ fn user_input( // System that moves the enemies in a circle. // Only runs if there are enemies, due to the `Populated` parameter. -fn move_targets(mut enemies: Populated<(&mut Transform, &mut Enemy)>, time: Res