1use crate::{component::Component, entity::Entity, query::QueryData};
4
5use alloc::{
6 borrow::{Cow, ToOwned},
7 string::String,
8};
9use bevy_platform::hash::Hashed;
10use core::{
11 hash::{Hash, Hasher},
12 ops::Deref,
13};
14
15#[cfg(feature = "serialize")]
16use {
17 alloc::string::ToString,
18 serde::{
19 de::{Error, Visitor},
20 Deserialize, Deserializer, Serialize, Serializer,
21 },
22};
23
24#[cfg(feature = "bevy_reflect")]
25use {
26 crate::reflect::ReflectComponent,
27 bevy_reflect::{std_traits::ReflectDefault, Reflect},
28};
29
30#[cfg(all(feature = "serialize", feature = "bevy_reflect"))]
31use bevy_reflect::{ReflectDeserialize, ReflectSerialize};
32
33#[derive(Component, Clone)]
41#[cfg_attr(
42 feature = "bevy_reflect",
43 derive(Reflect),
44 reflect(Component, Default, Debug, Clone, Hash, PartialEq)
45)]
46#[cfg_attr(
47 all(feature = "serialize", feature = "bevy_reflect"),
48 reflect(Deserialize, Serialize)
49)]
50pub struct Name(pub HashedStr);
51
52impl Default for Name {
53 fn default() -> Self {
54 Name::new("")
55 }
56}
57
58#[derive(Clone)]
60#[cfg_attr(feature = "bevy_reflect", derive(Reflect))]
61pub struct HashedStr(Hashed<Cow<'static, str>>);
62
63impl From<&'static str> for HashedStr {
64 fn from(value: &'static str) -> Self {
65 Self(Hashed::new(Cow::Borrowed(value)))
66 }
67}
68
69impl From<String> for HashedStr {
70 fn from(value: String) -> Self {
71 Self(Hashed::new(Cow::Owned(value)))
72 }
73}
74
75impl Name {
76 pub fn new(name: impl Into<Cow<'static, str>>) -> Self {
80 Self(HashedStr(Hashed::new(name.into())))
81 }
82
83 #[inline(always)]
87 pub fn set(&mut self, name: impl Into<Cow<'static, str>>) {
88 *self = Name::new(name);
89 }
90
91 #[inline(always)]
96 pub fn mutate(&mut self, func: impl FnOnce(&mut String)) {
97 self.0 .0.mutate(|cow_str| match cow_str {
98 Cow::Borrowed(borrowed) => {
99 let mut owned = borrowed.to_owned();
100 func(&mut owned);
101 *cow_str = Cow::Owned(owned);
102 }
103 Cow::Owned(owned) => {
104 func(owned);
105 }
106 });
107 }
108
109 #[inline(always)]
111 pub fn as_str(&self) -> &str {
112 &self.0 .0
113 }
114 #[inline(always)]
116 pub fn pre_hash(&self) -> u64 {
117 self.0 .0.hash()
118 }
119}
120
121impl core::fmt::Display for Name {
122 #[inline(always)]
123 fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
124 core::fmt::Display::fmt(&*self.0 .0, f)
125 }
126}
127
128impl core::fmt::Debug for Name {
129 #[inline(always)]
130 fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
131 core::fmt::Debug::fmt(&self.0 .0, f)
132 }
133}
134
135#[derive(QueryData)]
156#[query_data(derive(Debug))]
157pub struct NameOrEntity {
158 pub name: Option<&'static Name>,
160 pub entity: Entity,
162}
163
164impl<'w, 's> core::fmt::Display for NameOrEntityItem<'w, 's> {
165 #[inline(always)]
166 fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
167 match self.name {
168 Some(name) => core::fmt::Display::fmt(name, f),
169 None => core::fmt::Display::fmt(&self.entity, f),
170 }
171 }
172}
173
174impl From<&str> for Name {
177 #[inline(always)]
178 fn from(name: &str) -> Self {
179 Name::new(name.to_owned())
180 }
181}
182
183impl From<String> for Name {
184 #[inline(always)]
185 fn from(name: String) -> Self {
186 Name::new(name)
187 }
188}
189
190impl AsRef<str> for Name {
193 #[inline(always)]
194 fn as_ref(&self) -> &str {
195 &self.0 .0
196 }
197}
198
199impl From<&Name> for String {
200 #[inline(always)]
201 fn from(val: &Name) -> String {
202 val.as_str().to_owned()
203 }
204}
205
206impl From<Name> for String {
207 #[inline(always)]
208 fn from(val: Name) -> String {
209 val.as_str().to_owned()
210 }
211}
212
213impl Hash for Name {
214 fn hash<H: Hasher>(&self, state: &mut H) {
215 Hash::hash(&self.0 .0, state);
216 }
217}
218
219impl PartialEq for Name {
220 fn eq(&self, other: &Self) -> bool {
221 if self.0 .0.hash() != other.0 .0.hash() {
222 return false;
224 }
225
226 self.0 .0.eq(&other.0 .0)
227 }
228}
229
230impl Eq for Name {}
231
232impl PartialOrd for Name {
233 fn partial_cmp(&self, other: &Self) -> Option<core::cmp::Ordering> {
234 Some(self.cmp(other))
235 }
236}
237
238impl Ord for Name {
239 fn cmp(&self, other: &Self) -> core::cmp::Ordering {
240 self.0 .0.cmp(&other.0 .0)
241 }
242}
243
244impl Deref for Name {
245 type Target = str;
246
247 fn deref(&self) -> &Self::Target {
248 self.as_str()
249 }
250}
251
252#[cfg(feature = "serialize")]
253impl Serialize for Name {
254 fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
255 serializer.serialize_str(self.as_str())
256 }
257}
258
259#[cfg(feature = "serialize")]
260impl<'de> Deserialize<'de> for Name {
261 fn deserialize<D: Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
262 deserializer.deserialize_str(NameVisitor)
263 }
264}
265
266#[cfg(feature = "serialize")]
267struct NameVisitor;
268
269#[cfg(feature = "serialize")]
270impl<'de> Visitor<'de> for NameVisitor {
271 type Value = Name;
272
273 fn expecting(&self, formatter: &mut core::fmt::Formatter) -> core::fmt::Result {
274 formatter.write_str(core::any::type_name::<Name>())
275 }
276
277 fn visit_str<E: Error>(self, v: &str) -> Result<Self::Value, E> {
278 Ok(Name::new(v.to_string()))
279 }
280
281 fn visit_string<E: Error>(self, v: String) -> Result<Self::Value, E> {
282 Ok(Name::new(v))
283 }
284}
285
286#[cfg(test)]
287mod tests {
288 use super::*;
289 use crate::world::World;
290 use alloc::string::ToString;
291 use bevy_platform::hash::fixed_hash_one;
292
293 #[test]
294 fn test_display_of_debug_name() {
295 let mut world = World::new();
296 let e1 = world.spawn_empty().id();
297 let name = Name::new("MyName");
298 let e2 = world.spawn(name.clone()).id();
299 let mut query = world.query::<NameOrEntity>();
300 let d1 = query.get(&world, e1).unwrap();
301 assert_eq!(d1.to_string(), "1v0");
303 let d2 = query.get(&world, e2).unwrap();
304 assert_eq!(d2.to_string(), "MyName");
306 }
307 #[test]
308 fn test_name_hash_is_fixed() {
309 let str = "foobar";
310 assert_eq!(Name::from(str).pre_hash(), fixed_hash_one(str));
311 }
312}
313
314#[cfg(all(test, feature = "serialize"))]
315mod serde_tests {
316 use super::Name;
317
318 use serde_test::{assert_tokens, Token};
319
320 #[test]
321 fn test_serde_name() {
322 let name = Name::new("MyComponent");
323 assert_tokens(&name, &[Token::String("MyComponent")]);
324 }
325}