bevy_core/
name.rs

1use bevy_ecs::query::QueryData;
2use bevy_ecs::{component::Component, entity::Entity, reflect::ReflectComponent};
3
4use bevy_reflect::std_traits::ReflectDefault;
5use bevy_reflect::Reflect;
6use bevy_utils::AHasher;
7use std::{
8    borrow::Cow,
9    hash::{Hash, Hasher},
10    ops::Deref,
11};
12
13#[cfg(feature = "serialize")]
14use bevy_reflect::{ReflectDeserialize, ReflectSerialize};
15
16/// Component used to identify an entity. Stores a hash for faster comparisons.
17///
18/// The hash is eagerly re-computed upon each update to the name.
19///
20/// [`Name`] should not be treated as a globally unique identifier for entities,
21/// as multiple entities can have the same name.  [`Entity`] should be
22/// used instead as the default unique identifier.
23#[derive(Reflect, Component, Clone)]
24#[reflect(Component, Default, Debug)]
25#[cfg_attr(feature = "serialize", reflect(Serialize, Deserialize))]
26pub struct Name {
27    hash: u64, // Won't be serialized (see: `bevy_core::serde` module)
28    name: Cow<'static, str>,
29}
30
31impl Default for Name {
32    fn default() -> Self {
33        Name::new("")
34    }
35}
36
37impl Name {
38    /// Creates a new [`Name`] from any string-like type.
39    ///
40    /// The internal hash will be computed immediately.
41    pub fn new(name: impl Into<Cow<'static, str>>) -> Self {
42        let name = name.into();
43        let mut name = Name { name, hash: 0 };
44        name.update_hash();
45        name
46    }
47
48    /// Sets the entity's name.
49    ///
50    /// The internal hash will be re-computed.
51    #[inline(always)]
52    pub fn set(&mut self, name: impl Into<Cow<'static, str>>) {
53        *self = Name::new(name);
54    }
55
56    /// Updates the name of the entity in place.
57    ///
58    /// This will allocate a new string if the name was previously
59    /// created from a borrow.
60    #[inline(always)]
61    pub fn mutate<F: FnOnce(&mut String)>(&mut self, f: F) {
62        f(self.name.to_mut());
63        self.update_hash();
64    }
65
66    /// Gets the name of the entity as a `&str`.
67    #[inline(always)]
68    pub fn as_str(&self) -> &str {
69        &self.name
70    }
71
72    fn update_hash(&mut self) {
73        let mut hasher = AHasher::default();
74        self.name.hash(&mut hasher);
75        self.hash = hasher.finish();
76    }
77}
78
79impl std::fmt::Display for Name {
80    #[inline(always)]
81    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
82        std::fmt::Display::fmt(&self.name, f)
83    }
84}
85
86impl std::fmt::Debug for Name {
87    #[inline(always)]
88    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
89        std::fmt::Debug::fmt(&self.name, f)
90    }
91}
92
93/// Convenient query for giving a human friendly name to an entity.
94///
95/// ```
96/// # use bevy_core::prelude::*;
97/// # use bevy_ecs::prelude::*;
98/// # #[derive(Component)] pub struct Score(f32);
99/// fn increment_score(mut scores: Query<(DebugName, &mut Score)>) {
100///     for (name, mut score) in &mut scores {
101///         score.0 += 1.0;
102///         if score.0.is_nan() {
103///             bevy_utils::tracing::error!("Score for {:?} is invalid", name);
104///         }
105///     }
106/// }
107/// # bevy_ecs::system::assert_is_system(increment_score);
108/// ```
109#[derive(QueryData)]
110pub struct DebugName {
111    /// A [`Name`] that the entity might have that is displayed if available.
112    pub name: Option<&'static Name>,
113    /// The unique identifier of the entity as a fallback.
114    pub entity: Entity,
115}
116
117impl<'a> std::fmt::Debug for DebugNameItem<'a> {
118    #[inline(always)]
119    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
120        match self.name {
121            Some(name) => write!(f, "{:?} ({:?})", &name, &self.entity),
122            None => std::fmt::Debug::fmt(&self.entity, f),
123        }
124    }
125}
126
127/* Conversions from strings */
128
129impl From<&str> for Name {
130    #[inline(always)]
131    fn from(name: &str) -> Self {
132        Name::new(name.to_owned())
133    }
134}
135impl From<String> for Name {
136    #[inline(always)]
137    fn from(name: String) -> Self {
138        Name::new(name)
139    }
140}
141
142/* Conversions to strings */
143
144impl AsRef<str> for Name {
145    #[inline(always)]
146    fn as_ref(&self) -> &str {
147        &self.name
148    }
149}
150impl From<&Name> for String {
151    #[inline(always)]
152    fn from(val: &Name) -> String {
153        val.as_str().to_owned()
154    }
155}
156impl From<Name> for String {
157    #[inline(always)]
158    fn from(val: Name) -> String {
159        val.name.into_owned()
160    }
161}
162
163impl Hash for Name {
164    fn hash<H: Hasher>(&self, state: &mut H) {
165        self.name.hash(state);
166    }
167}
168
169impl PartialEq for Name {
170    fn eq(&self, other: &Self) -> bool {
171        if self.hash != other.hash {
172            // Makes the common case of two strings not been equal very fast
173            return false;
174        }
175
176        self.name.eq(&other.name)
177    }
178}
179
180impl Eq for Name {}
181
182impl PartialOrd for Name {
183    fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
184        Some(self.cmp(other))
185    }
186}
187
188impl Ord for Name {
189    fn cmp(&self, other: &Self) -> std::cmp::Ordering {
190        self.name.cmp(&other.name)
191    }
192}
193
194impl Deref for Name {
195    type Target = str;
196
197    fn deref(&self) -> &Self::Target {
198        self.name.as_ref()
199    }
200}