From 1df811e6a563b59dfb7f5f5eea52d03ec78fb6dd Mon Sep 17 00:00:00 2001 From: Gagnus <20407779+gagnus@users.noreply.github.com> Date: Tue, 25 Jun 2024 13:58:53 +0100 Subject: [PATCH] Add Display implementation to DebugName. (#13760) # Objective - When writing "in game" debugging tools, quite often you need the name of an entity (for example an entity tree). DebugName is the usual way of doing that. - A recent change to Entity's Debug implementation meant it was no longer a minimal {index}v{generation} but instead a more verbose auto generated Debug. - This made DebugName's Debug implementation also verbose ## Solution - I changed DebugName to derive Debug automatically and added a new (preferred) Display implementation for it which is the preferred name for an entity. If the entity has a Name component its the contents of that, otherwise it is {index}v{generation} (though this does not use Display of the Entity as that is more verbose than this). ## Testing - I've added a new test in name.rs which tests the Display implementation for DebugName by using to_string. --- ## Migration Guide - In code which uses DebugName you should now use the Display implementation rather than the Debug implementation (ie {} instead of {:?} if you were printing it out). --------- Co-authored-by: John Payne <20407779+johngpayne@users.noreply.github.com> Co-authored-by: Jan Hohenheim Co-authored-by: Andres O. Vela --- crates/bevy_core/src/name.rs | 35 +++++++++++++++++++++++++++++++---- 1 file changed, 31 insertions(+), 4 deletions(-) diff --git a/crates/bevy_core/src/name.rs b/crates/bevy_core/src/name.rs index dfa4a11c11..c3012224ad 100644 --- a/crates/bevy_core/src/name.rs +++ b/crates/bevy_core/src/name.rs @@ -100,13 +100,19 @@ impl std::fmt::Debug for Name { /// for (name, mut score) in &mut scores { /// score.0 += 1.0; /// if score.0.is_nan() { -/// bevy_utils::tracing::error!("Score for {:?} is invalid", name); +/// bevy_utils::tracing::error!("Score for {name} is invalid"); /// } /// } /// } /// # bevy_ecs::system::assert_is_system(increment_score); /// ``` +/// +/// # Implementation +/// +/// The `Display` impl for `DebugName` returns the `Name` where there is one +/// or {index}v{generation} for entities without one. #[derive(QueryData)] +#[query_data(derive(Debug))] pub struct DebugName { /// A [`Name`] that the entity might have that is displayed if available. pub name: Option<&'static Name>, @@ -114,12 +120,12 @@ pub struct DebugName { pub entity: Entity, } -impl<'a> std::fmt::Debug for DebugNameItem<'a> { +impl<'a> std::fmt::Display for DebugNameItem<'a> { #[inline(always)] fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { match self.name { - Some(name) => write!(f, "{:?} ({:?})", &name, &self.entity), - None => std::fmt::Debug::fmt(&self.entity, f), + Some(name) => std::fmt::Display::fmt(name, f), + None => write!(f, "{}v{}", self.entity.index(), self.entity.generation()), } } } @@ -198,3 +204,24 @@ impl Deref for Name { self.name.as_ref() } } + +#[cfg(test)] +mod tests { + use super::*; + use bevy_ecs::world::World; + + #[test] + fn test_display_of_debug_name() { + let mut world = World::new(); + let e1 = world.spawn_empty().id(); + let name = Name::new("MyName"); + let e2 = world.spawn(name.clone()).id(); + let mut query = world.query::(); + let d1 = query.get(&world, e1).unwrap(); + let d2 = query.get(&world, e2).unwrap(); + // DebugName Display for entities without a Name should be {index}v{generation} + assert_eq!(d1.to_string(), "0v1"); + // DebugName Display for entities with a Name should be the Name + assert_eq!(d2.to_string(), "MyName"); + } +}