diff --git a/crates/bevy_ecs/src/schedule/executor/mod.rs b/crates/bevy_ecs/src/schedule/executor/mod.rs index 655a71caa7..280dc33571 100644 --- a/crates/bevy_ecs/src/schedule/executor/mod.rs +++ b/crates/bevy_ecs/src/schedule/executor/mod.rs @@ -318,7 +318,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, }; @@ -341,12 +341,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; @@ -418,7 +418,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 } @@ -446,7 +446,11 @@ mod tests { } // 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; } @@ -499,7 +503,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 } @@ -523,7 +527,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(); @@ -555,13 +559,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 6e44301b18..c341df9886 100644 --- a/crates/bevy_ecs/src/system/query.rs +++ b/crates/bevy_ecs/src/system/query.rs @@ -2581,9 +2581,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. /// @@ -2632,7 +2634,9 @@ impl<'w, 's, D: QueryData, F: QueryFilter> Single<'w, 's, 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 d9b433e7f2..5050cc6153 100644 --- a/crates/bevy_ecs/src/system/system_param.rs +++ b/crates/bevy_ecs/src/system/system_param.rs @@ -448,10 +448,10 @@ unsafe impl<'a, 'b, D: QueryData + 'static, F: QueryFilter + 'static> SystemPara 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"), ), } } @@ -509,7 +509,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 { @@ -1836,6 +1836,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 2d238c1107..0479663372 100644 --- a/crates/bevy_input_focus/src/lib.rs +++ b/crates/bevy_input_focus/src/lib.rs @@ -243,10 +243,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 94a8007aec..6a32e66c50 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