From 1bad9913e8cff5f8a421e082145a5ce680e44bd7 Mon Sep 17 00:00:00 2001 From: Edvin Kjell Date: Sun, 11 Dec 2022 18:10:03 +0000 Subject: [PATCH] [Fixes #6224] Add logging variants of system piping (#6751) # Objective Fixes #6224, add ``dbg``, ``info``, ``warn`` and ``error`` system piping adapter variants to expand #5776, which call the corresponding re-exported [bevy_log macros](https://docs.rs/bevy/latest/bevy/log/macro.info.html) when the result is an error. ## Solution * Added ``dbg``, ``info``, ``warn`` and ``error`` system piping adapter variants to ``system_piping.rs``. * Modified and added tests for these under examples in ``system_piping.rs``. --- crates/bevy_ecs/src/lib.rs | 7 +- crates/bevy_ecs/src/system/system_piping.rs | 137 ++++++++++++++++++++ examples/ecs/system_piping.rs | 36 ++++- 3 files changed, 176 insertions(+), 4 deletions(-) diff --git a/crates/bevy_ecs/src/lib.rs b/crates/bevy_ecs/src/lib.rs index aa6add8c84909..d4f79bec0f9ad 100644 --- a/crates/bevy_ecs/src/lib.rs +++ b/crates/bevy_ecs/src/lib.rs @@ -38,9 +38,10 @@ pub mod prelude { Schedule, Stage, StageLabel, State, SystemLabel, SystemSet, SystemStage, }, system::{ - adapter as system_adapter, Commands, In, IntoPipeSystem, IntoSystem, Local, NonSend, - NonSendMut, ParallelCommands, ParamSet, Query, RemovedComponents, Res, ResMut, - Resource, System, SystemParamFunction, + adapter as system_adapter, + adapter::{dbg, error, ignore, info, unwrap, warn}, + Commands, In, IntoPipeSystem, IntoSystem, Local, NonSend, NonSendMut, ParallelCommands, + ParamSet, Query, RemovedComponents, Res, ResMut, Resource, System, SystemParamFunction, }, world::{FromWorld, Mut, World}, }; diff --git a/crates/bevy_ecs/src/system/system_piping.rs b/crates/bevy_ecs/src/system/system_piping.rs index 09533a02c32b5..d28158b697836 100644 --- a/crates/bevy_ecs/src/system/system_piping.rs +++ b/crates/bevy_ecs/src/system/system_piping.rs @@ -167,6 +167,7 @@ where /// A collection of common adapters for [piping](super::PipeSystem) the result of a system. pub mod adapter { use crate::system::In; + use bevy_utils::tracing; use std::fmt::Debug; /// Converts a regular function into a system adapter. @@ -232,6 +233,142 @@ pub mod adapter { res.unwrap() } + /// System adapter that utilizes the [`bevy_utils::tracing::info!`] macro to print system information. + /// + /// # Examples + /// + /// ``` + /// use bevy_ecs::prelude::*; + /// # + /// # #[derive(StageLabel)] + /// # enum CoreStage { Update }; + /// + /// // Building a new schedule/app... + /// # use bevy_ecs::schedule::SystemStage; + /// # let mut sched = Schedule::default(); sched + /// # .add_stage(CoreStage::Update, SystemStage::parallel()) + /// .add_system_to_stage( + /// CoreStage::Update, + /// // Prints system information. + /// data_pipe_system.pipe(system_adapter::info) + /// ) + /// // ... + /// # ; + /// # let mut world = World::new(); + /// # sched.run(&mut world); + /// + /// // A system that returns a String output. + /// fn data_pipe_system() -> String { + /// "42".to_string() + /// } + /// ``` + pub fn info(In(data): In) { + tracing::info!("{:?}", data); + } + + /// System adapter that utilizes the [`bevy_utils::tracing::debug!`] macro to print the output of a system. + /// + /// # Examples + /// + /// ``` + /// use bevy_ecs::prelude::*; + /// # + /// # #[derive(StageLabel)] + /// # enum CoreStage { Update }; + /// + /// // Building a new schedule/app... + /// # use bevy_ecs::schedule::SystemStage; + /// # let mut sched = Schedule::default(); sched + /// # .add_stage(CoreStage::Update, SystemStage::parallel()) + /// .add_system_to_stage( + /// CoreStage::Update, + /// // Prints debug data from system. + /// parse_message_system.pipe(system_adapter::dbg) + /// ) + /// // ... + /// # ; + /// # let mut world = World::new(); + /// # sched.run(&mut world); + /// + /// // A system that returns a Result output. + /// fn parse_message_system() -> Result { + /// Ok("42".parse()?) + /// } + /// ``` + pub fn dbg(In(data): In) { + tracing::debug!("{:?}", data); + } + + /// System adapter that utilizes the [`bevy_utils::tracing::warn!`] macro to print the output of a system. + /// + /// # Examples + /// + /// ``` + /// use bevy_ecs::prelude::*; + /// # + /// # #[derive(StageLabel)] + /// # enum CoreStage { Update }; + /// + /// // Building a new schedule/app... + /// # use bevy_ecs::schedule::SystemStage; + /// # let mut sched = Schedule::default(); sched + /// # .add_stage(CoreStage::Update, SystemStage::parallel()) + /// .add_system_to_stage( + /// CoreStage::Update, + /// // Prints system warning if system returns an error. + /// warning_pipe_system.pipe(system_adapter::warn) + /// ) + /// // ... + /// # ; + /// # let mut world = World::new(); + /// # sched.run(&mut world); + /// + /// // A system that returns a Result<(), String> output. + /// fn warning_pipe_system() -> Result<(), String> { + /// Err("Got to rusty?".to_string()) + /// } + /// ``` + pub fn warn(In(res): In>) { + if let Err(warn) = res { + tracing::warn!("{:?}", warn); + } + } + + /// System adapter that utilizes the [`bevy_utils::tracing::error!`] macro to print the output of a system. + /// + /// # Examples + /// + /// ``` + /// use bevy_ecs::prelude::*; + /// # + /// # #[derive(StageLabel)] + /// # enum CoreStage { Update }; + /// + /// // Building a new schedule/app... + /// # use bevy_ecs::schedule::SystemStage; + /// # let mut sched = Schedule::default(); sched + /// # .add_stage(CoreStage::Update, SystemStage::parallel()) + /// .add_system_to_stage( + /// CoreStage::Update, + /// // Prints system error if system fails. + /// parse_error_message_system.pipe(system_adapter::error) + /// ) + /// // ... + /// # ; + /// # let mut world = World::new(); + /// # sched.run(&mut world); + /// + /// // A system that returns a Result<())> output. + /// fn parse_error_message_system() -> Result<(), String> { + /// Err("Some error".to_owned()) + /// } + /// ``` + pub fn error(In(res): In>) { + if let Err(error) = res { + tracing::error!("{:?}", error); + } + } + /// System adapter that ignores the output of the previous system in a pipe. /// This is useful for fallible systems that should simply return early in case of an `Err`/`None`. /// diff --git a/examples/ecs/system_piping.rs b/examples/ecs/system_piping.rs index 01e7db60037d1..da06a0640856e 100644 --- a/examples/ecs/system_piping.rs +++ b/examples/ecs/system_piping.rs @@ -4,21 +4,43 @@ use anyhow::Result; use bevy::prelude::*; +use bevy::log::LogPlugin; +use bevy::utils::tracing::Level; + fn main() { App::new() .insert_resource(Message("42".to_string())) + .insert_resource(OptionalWarning(Err("Got to rusty?".to_string()))) + .add_plugin(LogPlugin { + level: Level::TRACE, + filter: "".to_string(), + }) .add_system(parse_message_system.pipe(handler_system)) + .add_system(data_pipe_system.pipe(info)) + .add_system(parse_message_system.pipe(dbg)) + .add_system(warning_pipe_system.pipe(warn)) + .add_system(parse_error_message_system.pipe(error)) + .add_system(parse_message_system.pipe(ignore)) .run(); } #[derive(Resource, Deref)] struct Message(String); -// this system produces a Result output by trying to parse the Message resource +#[derive(Resource, Deref)] +struct OptionalWarning(Result<(), String>); + +// This system produces a Result output by trying to parse the Message resource. fn parse_message_system(message: Res) -> Result { Ok(message.parse::()?) } +// This system produces a Result<()> output by trying to parse the Message resource. +fn parse_error_message_system(message: Res) -> Result<()> { + message.parse::()?; + Ok(()) +} + // This system takes a Result input and either prints the parsed value or the error message // Try changing the Message resource to something that isn't an integer. You should see the error // message printed. @@ -28,3 +50,15 @@ fn handler_system(In(result): In>) { Err(err) => println!("encountered an error: {err:?}"), } } + +// This system produces a String output by trying to clone the String from the Message resource. +fn data_pipe_system(message: Res) -> String { + message.0.clone() +} + +// This system produces an Result output by trying to extract a String from the +// OptionalWarning resource. Try changing the OptionalWarning resource to None. You should +// not see the warning message printed. +fn warning_pipe_system(message: Res) -> Result<(), String> { + message.0.clone() +}