From a61fac20ca5e34255b76bb4b17835a6f8227258f Mon Sep 17 00:00:00 2001 From: JoJoJet <21144246+JoJoJet@users.noreply.github.com> Date: Tue, 7 Feb 2023 08:00:35 -0500 Subject: [PATCH 1/6] add the `ReadOnlySystem` trait --- crates/bevy_ecs/src/system/function_system.rs | 13 +++++++++++++ crates/bevy_ecs/src/system/system.rs | 5 +++++ crates/bevy_ecs/src/system/system_piping.rs | 11 +++++++++++ 3 files changed, 29 insertions(+) diff --git a/crates/bevy_ecs/src/system/function_system.rs b/crates/bevy_ecs/src/system/function_system.rs index b1e4c73e86332..a95a108bdc066 100644 --- a/crates/bevy_ecs/src/system/function_system.rs +++ b/crates/bevy_ecs/src/system/function_system.rs @@ -10,6 +10,8 @@ use crate::{ use bevy_ecs_macros::all_tuples; use std::{any::TypeId, borrow::Cow, marker::PhantomData}; +use super::ReadOnlySystem; + /// The metadata of a [`System`]. #[derive(Clone)] pub struct SystemMeta { @@ -528,6 +530,17 @@ where } } +/// SAFETY: `F`'s param is `ReadOnlySystemParam`, so this system will only read from the world. +unsafe impl ReadOnlySystem for FunctionSystem +where + In: 'static, + Out: 'static, + Param: ReadOnlySystemParam + 'static, + Marker: 'static, + F: SystemParamFunction + Send + Sync + 'static, +{ +} + /// A trait implemented for all functions that can be used as [`System`]s. /// /// This trait can be useful for making your own systems which accept other systems, diff --git a/crates/bevy_ecs/src/system/system.rs b/crates/bevy_ecs/src/system/system.rs index dbbe58156834f..cd9974230bd38 100644 --- a/crates/bevy_ecs/src/system/system.rs +++ b/crates/bevy_ecs/src/system/system.rs @@ -78,6 +78,11 @@ pub trait System: Send + Sync + 'static { fn set_last_change_tick(&mut self, last_change_tick: u32); } +/// # Safety +/// +/// This must only be implemented for system types which do not read from the [`World`]. +pub unsafe trait ReadOnlySystem: System {} + /// A convenience type alias for a boxed [`System`] trait object. pub type BoxedSystem = Box>; diff --git a/crates/bevy_ecs/src/system/system_piping.rs b/crates/bevy_ecs/src/system/system_piping.rs index 62eb057defc94..8559e37bfc6a7 100644 --- a/crates/bevy_ecs/src/system/system_piping.rs +++ b/crates/bevy_ecs/src/system/system_piping.rs @@ -7,6 +7,8 @@ use crate::{ }; use std::{any::TypeId, borrow::Cow}; +use super::ReadOnlySystem; + /// A [`System`] created by piping the output of the first system into the input of the second. /// /// This can be repeated indefinitely, but system pipes cannot branch: the output is consumed by the receiving system. @@ -153,6 +155,15 @@ impl> System for PipeSystem< } } +/// SAFETY: Both systems are read-only, so piping them together will only read from the world. +unsafe impl> ReadOnlySystem + for PipeSystem +where + SystemA: ReadOnlySystem, + SystemB: ReadOnlySystem, +{ +} + /// An extension trait providing the [`IntoPipeSystem::pipe`] method to pass input from one system into the next. /// /// The first system must have return type `T` From 8379882352e90c13fc0f72aca89aaf29e8de407f Mon Sep 17 00:00:00 2001 From: JoJoJet <21144246+JoJoJet@users.noreply.github.com> Date: Tue, 7 Feb 2023 08:04:56 -0500 Subject: [PATCH 2/6] add a small test case for piping run conditions --- crates/bevy_ecs/src/system/system_piping.rs | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/crates/bevy_ecs/src/system/system_piping.rs b/crates/bevy_ecs/src/system/system_piping.rs index 8559e37bfc6a7..4787fccd469d0 100644 --- a/crates/bevy_ecs/src/system/system_piping.rs +++ b/crates/bevy_ecs/src/system/system_piping.rs @@ -423,10 +423,16 @@ pub mod adapter { unimplemented!() } + fn not(In(val): In) -> bool { + !val + } + assert_is_system(returning::>.pipe(unwrap)); assert_is_system(returning::>.pipe(ignore)); assert_is_system(returning::<&str>.pipe(new(u64::from_str)).pipe(unwrap)); assert_is_system(exclusive_in_out::<(), Result<(), std::io::Error>>.pipe(error)); assert_is_system(returning::.pipe(exclusive_in_out::)); + + returning::<()>.run_if(returning::.pipe(not)); } } From 6ccd47bb1a18b91b408b41ea7786c9a456d53bfd Mon Sep 17 00:00:00 2001 From: JoJoJet <21144246+JoJoJet@users.noreply.github.com> Date: Tue, 7 Feb 2023 08:07:24 -0500 Subject: [PATCH 3/6] allow any `ReadOnlySystem` to be used as a run condition --- crates/bevy_ecs/src/schedule/condition.rs | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/crates/bevy_ecs/src/schedule/condition.rs b/crates/bevy_ecs/src/schedule/condition.rs index 7ee6c1723213d..541ed202957b6 100644 --- a/crates/bevy_ecs/src/schedule/condition.rs +++ b/crates/bevy_ecs/src/schedule/condition.rs @@ -11,15 +11,14 @@ pub trait Condition: sealed::Condition {} impl Condition for F where F: sealed::Condition {} mod sealed { - use crate::system::{IntoSystem, IsFunctionSystem, ReadOnlySystemParam, SystemParamFunction}; + use crate::system::{IntoSystem, ReadOnlySystem}; pub trait Condition: IntoSystem<(), bool, Params> {} - impl Condition<(IsFunctionSystem, Params, Marker)> for F + impl Condition for F where - F: SystemParamFunction<(), bool, Params, Marker> + Send + Sync + 'static, - Params: ReadOnlySystemParam + 'static, - Marker: 'static, + F: IntoSystem<(), bool, Params>, + F::System: ReadOnlySystem, { } } From 79a70469d35fd5ab4b4d768fb1cba084b2c3e525 Mon Sep 17 00:00:00 2001 From: JoJoJet <21144246+JoJoJet@users.noreply.github.com> Date: Tue, 7 Feb 2023 11:53:31 -0500 Subject: [PATCH 4/6] add more docs to `ReadOnlySystem` --- crates/bevy_ecs/src/system/system.rs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/crates/bevy_ecs/src/system/system.rs b/crates/bevy_ecs/src/system/system.rs index cd9974230bd38..f0147229e1a76 100644 --- a/crates/bevy_ecs/src/system/system.rs +++ b/crates/bevy_ecs/src/system/system.rs @@ -78,9 +78,11 @@ pub trait System: Send + Sync + 'static { fn set_last_change_tick(&mut self, last_change_tick: u32); } +/// [`System`] types that do not modify the [`World`] when run. +/// /// # Safety /// -/// This must only be implemented for system types which do not read from the [`World`]. +/// This must only be implemented for system types which do not mutate the `World`. pub unsafe trait ReadOnlySystem: System {} /// A convenience type alias for a boxed [`System`] trait object. From 6b7cf9cae4d7cdf9e76afc124ef8cfb7b1cb6d09 Mon Sep 17 00:00:00 2001 From: JoJoJet <21144246+JoJoJet@users.noreply.github.com> Date: Tue, 7 Feb 2023 11:55:23 -0500 Subject: [PATCH 5/6] add `assert_is_read_only_system` --- crates/bevy_ecs/src/system/mod.rs | 20 ++++++++++++++++++-- 1 file changed, 18 insertions(+), 2 deletions(-) diff --git a/crates/bevy_ecs/src/system/mod.rs b/crates/bevy_ecs/src/system/mod.rs index 7b8922e79c72a..dab5dd654d825 100644 --- a/crates/bevy_ecs/src/system/mod.rs +++ b/crates/bevy_ecs/src/system/mod.rs @@ -117,11 +117,11 @@ pub use system::*; pub use system_param::*; pub use system_piping::*; -/// Ensure that a given function is a system +/// Ensure that a given function is a [system](System). /// /// This should be used when writing doc examples, /// to confirm that systems used in an example are -/// valid systems +/// valid systems. pub fn assert_is_system>(sys: S) { if false { // Check it can be converted into a system @@ -130,6 +130,22 @@ pub fn assert_is_system>(sys: S) } } +/// Ensure that a given function is a [read-only system](ReadOnlySystem). +/// +/// This should be used when writing doc examples, +/// to confirm that systems used in an example are +/// valid systems. +pub fn assert_is_read_only_system>(sys: S) +where + S::System: ReadOnlySystem, +{ + if false { + // Check it can be converted into a system + // TODO: This should ensure that the system has no conflicting system params + IntoSystem::into_system(sys); + } +} + #[cfg(test)] mod tests { use std::any::TypeId; From 00201001f26f8e776c8a459f4d1a69cfffb95198 Mon Sep 17 00:00:00 2001 From: JoJoJet <21144246+JoJoJet@users.noreply.github.com> Date: Tue, 7 Feb 2023 12:05:48 -0500 Subject: [PATCH 6/6] add another line to `ReadOnlySystem` docs --- crates/bevy_ecs/src/system/system.rs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/crates/bevy_ecs/src/system/system.rs b/crates/bevy_ecs/src/system/system.rs index f0147229e1a76..78980e9063b81 100644 --- a/crates/bevy_ecs/src/system/system.rs +++ b/crates/bevy_ecs/src/system/system.rs @@ -79,6 +79,9 @@ pub trait System: Send + Sync + 'static { } /// [`System`] types that do not modify the [`World`] when run. +/// This is implemented for any systems whose parameters all implement [`ReadOnlySystemParam`]. +/// +/// [`ReadOnlySystemParam`]: crate::system::ReadOnlySystemParam /// /// # Safety ///