Skip to content

Commit

Permalink
Adding Debug implementations for App, Stage, Schedule, Query, QuerySt…
Browse files Browse the repository at this point in the history
…ate, etc. (bevyengine#6214)

# Objective

- Adding Debug implementations for App, Stage, Schedule, Query, QueryState.
- Fixes bevyengine#1130.

## Solution

- Implemented std::fmt::Debug for a number of structures.

---

## Changelog

Also added Debug implementations for ParallelSystemExecutor, SingleThreadedExecutor, various RunCriteria structures, SystemContainer, and SystemDescriptor.

Opinions are sure to differ as to what information to provide in a Debug implementation.  Best guess was taken for this initial version for these structures.


Co-authored-by: targrub <62773321+targrub@users.noreply.github.com>
  • Loading branch information
2 people authored and james7132 committed Oct 28, 2022
1 parent 7e4983f commit cc609f3
Show file tree
Hide file tree
Showing 10 changed files with 202 additions and 6 deletions.
20 changes: 20 additions & 0 deletions crates/bevy_app/src/app.rs
Expand Up @@ -70,12 +70,32 @@ pub struct App {
sub_apps: HashMap<AppLabelId, SubApp>,
}

impl Debug for App {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "App {{ sub_apps: ")?;
f.debug_map()
.entries(self.sub_apps.iter().map(|(k, v)| (k, v)))
.finish()?;
write!(f, "}}")
}
}

/// Each `SubApp` has its own [`Schedule`] and [`World`], enabling a separation of concerns.
struct SubApp {
app: App,
runner: Box<dyn Fn(&mut World, &mut App)>,
}

impl Debug for SubApp {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "SubApp {{ app: ")?;
f.debug_map()
.entries(self.app.sub_apps.iter().map(|(k, v)| (k, v)))
.finish()?;
write!(f, "}}")
}
}

impl Default for App {
fn default() -> Self {
let mut app = App::empty();
Expand Down
11 changes: 11 additions & 0 deletions crates/bevy_ecs/src/query/state.rs
Expand Up @@ -35,6 +35,17 @@ pub struct QueryState<Q: WorldQuery, F: ReadOnlyWorldQuery = ()> {
pub(crate) filter_state: F::State,
}

impl<Q: WorldQuery, F: ReadOnlyWorldQuery> std::fmt::Debug for QueryState<Q, F> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(
f,
"QueryState<Q, F> matched_table_ids: {} matched_archetype_ids: {}",
self.matched_table_ids.len(),
self.matched_archetype_ids.len()
)
}
}

impl<Q: WorldQuery, F: ReadOnlyWorldQuery> FromWorld for QueryState<Q, F> {
fn from_world(world: &mut World) -> Self {
world.query_filtered()
Expand Down
9 changes: 8 additions & 1 deletion crates/bevy_ecs/src/schedule/executor.rs
@@ -1,4 +1,5 @@
use crate::{schedule::SystemContainer, world::World};
use core::fmt::Debug;
use downcast_rs::{impl_downcast, Downcast};

pub trait ParallelSystemExecutor: Downcast + Send + Sync {
Expand All @@ -8,9 +9,15 @@ pub trait ParallelSystemExecutor: Downcast + Send + Sync {
fn run_systems(&mut self, systems: &mut [SystemContainer], world: &mut World);
}

impl Debug for dyn ParallelSystemExecutor {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "dyn ParallelSystemExecutor")
}
}

impl_downcast!(ParallelSystemExecutor);

#[derive(Default)]
#[derive(Debug, Default)]
pub struct SingleThreadedExecutor;

impl ParallelSystemExecutor for SingleThreadedExecutor {
Expand Down
2 changes: 1 addition & 1 deletion crates/bevy_ecs/src/schedule/mod.rs
Expand Up @@ -37,7 +37,7 @@ use bevy_utils::HashMap;
/// In this way, the properties of the child schedule can be set differently from the parent.
/// For example, it can be set to run only once during app execution, while the parent schedule
/// runs indefinitely.
#[derive(Default)]
#[derive(Debug, Default)]
pub struct Schedule {
stages: HashMap<StageLabelId, Box<dyn Stage>>,
stage_order: Vec<StageLabelId>,
Expand Down
58 changes: 56 additions & 2 deletions crates/bevy_ecs/src/schedule/run_criteria.rs
@@ -1,8 +1,10 @@
use crate::{
prelude::System,
schedule::{GraphNode, RunCriteriaLabel, RunCriteriaLabelId},
system::{BoxedSystem, IntoSystem, Local},
world::World,
};
use core::fmt::Debug;
use std::borrow::Cow;

/// Determines whether a system should be executed or not, and how many times it should be ran each
Expand Down Expand Up @@ -66,7 +68,7 @@ impl From<bool> for ShouldRun {
}
}

#[derive(Default)]
#[derive(Debug, Default)]
pub(crate) struct BoxedRunCriteria {
criteria_system: Option<BoxedSystem<(), ShouldRun>>,
initialized: bool,
Expand All @@ -93,6 +95,7 @@ impl BoxedRunCriteria {
}
}

#[derive(Debug)]
pub(crate) enum RunCriteriaInner {
Single(BoxedSystem<(), ShouldRun>),
Piped {
Expand All @@ -101,6 +104,7 @@ pub(crate) enum RunCriteriaInner {
},
}

#[derive(Debug)]
pub(crate) struct RunCriteriaContainer {
pub(crate) should_run: ShouldRun,
pub(crate) inner: RunCriteriaInner,
Expand Down Expand Up @@ -165,17 +169,19 @@ impl GraphNode for RunCriteriaContainer {
}
}

#[derive(Debug)]
pub enum RunCriteriaDescriptorOrLabel {
Descriptor(RunCriteriaDescriptor),
Label(RunCriteriaLabelId),
}

#[derive(Clone, Copy)]
#[derive(Debug, Clone, Copy)]
pub(crate) enum DuplicateLabelStrategy {
Panic,
Discard,
}

#[derive(Debug)]
pub struct RunCriteriaDescriptor {
pub(crate) system: RunCriteriaSystem,
pub(crate) label: Option<RunCriteriaLabelId>,
Expand All @@ -184,6 +190,7 @@ pub struct RunCriteriaDescriptor {
pub(crate) after: Vec<RunCriteriaLabelId>,
}

#[derive(Debug)]
pub(crate) enum RunCriteriaSystem {
Single(BoxedSystem<(), ShouldRun>),
Piped(BoxedSystem<ShouldRun, ShouldRun>),
Expand Down Expand Up @@ -326,6 +333,7 @@ where
}
}

#[derive(Debug)]
pub struct RunCriteria {
label: RunCriteriaLabelId,
}
Expand All @@ -346,3 +354,49 @@ impl RunCriteria {
}
}
}

impl Debug for dyn System<In = (), Out = ShouldRun> + 'static {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(
f,
"System {} with In=(), Out=ShouldRun: {{{}}}",
self.name(),
{
if self.is_send() {
if self.is_exclusive() {
"is_send is_exclusive"
} else {
"is_send"
}
} else if self.is_exclusive() {
"is_exclusive"
} else {
""
}
},
)
}
}

impl Debug for dyn System<In = ShouldRun, Out = ShouldRun> + 'static {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(
f,
"System {} with In=ShouldRun, Out=ShouldRun: {{{}}}",
self.name(),
{
if self.is_send() {
if self.is_exclusive() {
"is_send is_exclusive"
} else {
"is_send"
}
} else if self.is_exclusive() {
"is_exclusive"
} else {
""
}
},
)
}
}
73 changes: 72 additions & 1 deletion crates/bevy_ecs/src/schedule/stage.rs
Expand Up @@ -14,9 +14,10 @@ use crate::{
};
use bevy_ecs_macros::Resource;
use bevy_utils::{tracing::warn, HashMap, HashSet};
use core::fmt::Debug;
use downcast_rs::{impl_downcast, Downcast};

use super::IntoSystemDescriptor;
use super::{IntoSystemDescriptor, Schedule};

/// A type that can run as a step of a [`Schedule`](super::Schedule).
pub trait Stage: Downcast + Send + Sync {
Expand All @@ -25,6 +26,18 @@ pub trait Stage: Downcast + Send + Sync {
fn run(&mut self, world: &mut World);
}

impl Debug for dyn Stage {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
if let Some(as_systemstage) = self.as_any().downcast_ref::<SystemStage>() {
write!(f, "{:?}", as_systemstage)
} else if let Some(as_schedule) = self.as_any().downcast_ref::<Schedule>() {
write!(f, "{:?}", as_schedule)
} else {
write!(f, "Unknown dyn Stage")
}
}
}

impl_downcast!(Stage);

/// When this resource is present in the `App`'s `Resources`,
Expand Down Expand Up @@ -584,6 +597,64 @@ impl SystemStage {
}
Ok(labels)
}

pub fn vec_system_container_debug(
&self,
name: &str,
v: &Vec<SystemContainer>,
f: &mut std::fmt::Formatter<'_>,
) -> std::fmt::Result {
write!(f, "{}: ", name)?;
if v.len() > 1 {
writeln!(f, "[")?;
for sc in v.iter() {
writeln!(f, "{:?},", sc)?;
}
write!(f, "], ")
} else {
write!(f, "{:?}, ", v)
}
}
}

impl std::fmt::Debug for SystemStage {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "SystemStage: {{ ")?;
write!(
f,
"world_id: {:?}, executor: {:?}, stage_run_criteria: {:?}, run_criteria: {:?}, ",
self.world_id, self.executor, self.stage_run_criteria, self.run_criteria
)?;
self.vec_system_container_debug("exclusive_at_start", &self.exclusive_at_start, f)?;
self.vec_system_container_debug(
"exclusive_before_commands",
&self.exclusive_before_commands,
f,
)?;
self.vec_system_container_debug("exclusive_at_end", &self.exclusive_at_end, f)?;
self.vec_system_container_debug("parallel", &self.parallel, f)?;
write!(
f,
"systems_modified: {:?}, uninitialized_run_criteria: {:?}, ",
self.systems_modified, self.uninitialized_run_criteria
)?;
write!(
f,
"uninitialized_at_start: {:?}, uninitialized_before_commands: {:?}, ",
self.uninitialized_at_start, self.uninitialized_before_commands
)?;
write!(
f,
"uninitialized_at_end: {:?}, uninitialized_parallel: {:?}, ",
self.uninitialized_at_end, self.uninitialized_parallel
)?;
write!(
f,
"last_tick_check: {:?}, apply_buffers: {:?}, ",
self.last_tick_check, self.apply_buffers
)?;
write!(f, "must_read_resource: {:?}}}", self.must_read_resource)
}
}

/// Sorts given system containers topologically, populates their resolved dependencies
Expand Down
7 changes: 7 additions & 0 deletions crates/bevy_ecs/src/schedule/system_container.rs
Expand Up @@ -6,6 +6,7 @@ use crate::{
},
system::System,
};
use core::fmt::Debug;
use std::borrow::Cow;

pub struct SystemContainer {
Expand Down Expand Up @@ -83,6 +84,12 @@ impl SystemContainer {
}
}

impl Debug for SystemContainer {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "{{{:?}}}", &self.system())
}
}

impl GraphNode for SystemContainer {
type Label = SystemLabelId;

Expand Down
3 changes: 2 additions & 1 deletion crates/bevy_ecs/src/schedule/system_descriptor.rs
Expand Up @@ -4,7 +4,7 @@ use crate::{
};

/// Configures ambiguity detection for a single system.
#[derive(Default)]
#[derive(Debug, Default)]
pub(crate) enum AmbiguityDetection {
#[default]
Check,
Expand Down Expand Up @@ -41,6 +41,7 @@ pub(crate) enum AmbiguityDetection {
/// .with_system(do_the_other_thing.after(Something))
/// .with_system(do_something_else.at_end());
/// ```
#[derive(Debug)]
pub struct SystemDescriptor {
pub(crate) system: BoxedSystem<(), ()>,
pub(crate) exclusive_insertion_point: Option<ExclusiveInsertionPoint>,
Expand Down
6 changes: 6 additions & 0 deletions crates/bevy_ecs/src/system/query.rs
Expand Up @@ -280,6 +280,12 @@ pub struct Query<'world, 'state, Q: WorldQuery, F: ReadOnlyWorldQuery = ()> {
pub(crate) change_tick: u32,
}

impl<'w, 's, Q: WorldQuery, F: ReadOnlyWorldQuery> std::fmt::Debug for Query<'w, 's, Q, F> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "Query {{ matched entities: {}, world: {:?}, state: {:?}, last_change_tick: {}, change_tick: {} }}", self.iter().count(), self.world, self.state, self.last_change_tick, self.change_tick)
}
}

impl<'w, 's, Q: WorldQuery, F: ReadOnlyWorldQuery> Query<'w, 's, Q, F> {
/// Creates a new query.
///
Expand Down
19 changes: 19 additions & 0 deletions crates/bevy_ecs/src/system/system.rs
@@ -1,4 +1,5 @@
use bevy_utils::tracing::warn;
use core::fmt::Debug;

use crate::{
archetype::ArchetypeComponentId, change_detection::MAX_CHANGE_AGE, component::ComponentId,
Expand Down Expand Up @@ -95,3 +96,21 @@ pub(crate) fn check_system_change_tick(
*last_change_tick = change_tick.wrapping_sub(MAX_CHANGE_AGE);
}
}

impl Debug for dyn System<In = (), Out = ()> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "System {}: {{{}}}", self.name(), {
if self.is_send() {
if self.is_exclusive() {
"is_send is_exclusive"
} else {
"is_send"
}
} else if self.is_exclusive() {
"is_exclusive"
} else {
""
}
},)
}
}

0 comments on commit cc609f3

Please sign in to comment.