use crate::{component::Component, entity::Entity, query::QueryData};
use alloc::{
borrow::{Cow, ToOwned},
string::String,
};
use bevy_platform::hash::FixedHasher;
use core::{
hash::{BuildHasher, Hash, Hasher},
ops::Deref,
};
#[cfg(feature = "serialize")]
use {
alloc::string::ToString,
serde::{
de::{Error, Visitor},
Deserialize, Deserializer, Serialize, Serializer,
},
};
#[cfg(feature = "bevy_reflect")]
use {
crate::reflect::ReflectComponent,
bevy_reflect::{std_traits::ReflectDefault, Reflect},
};
#[cfg(all(feature = "serialize", feature = "bevy_reflect"))]
use bevy_reflect::{ReflectDeserialize, ReflectSerialize};
#[derive(Component, Clone)]
#[cfg_attr(
feature = "bevy_reflect",
derive(Reflect),
reflect(Component, Default, Debug, Clone, Hash, PartialEq)
)]
#[cfg_attr(
all(feature = "serialize", feature = "bevy_reflect"),
reflect(Deserialize, Serialize)
)]
pub struct Name {
hash: u64, name: Cow<'static, str>,
}
impl Default for Name {
fn default() -> Self {
Name::new("")
}
}
impl Name {
pub fn new(name: impl Into<Cow<'static, str>>) -> Self {
let name = name.into();
let mut name = Name { name, hash: 0 };
name.update_hash();
name
}
#[inline(always)]
pub fn set(&mut self, name: impl Into<Cow<'static, str>>) {
*self = Name::new(name);
}
#[inline(always)]
pub fn mutate<F: FnOnce(&mut String)>(&mut self, f: F) {
f(self.name.to_mut());
self.update_hash();
}
#[inline(always)]
pub fn as_str(&self) -> &str {
&self.name
}
fn update_hash(&mut self) {
self.hash = FixedHasher.hash_one(&self.name);
}
}
impl core::fmt::Display for Name {
#[inline(always)]
fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
core::fmt::Display::fmt(&self.name, f)
}
}
impl core::fmt::Debug for Name {
#[inline(always)]
fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
core::fmt::Debug::fmt(&self.name, f)
}
}
#[derive(QueryData)]
#[query_data(derive(Debug))]
pub struct NameOrEntity {
pub name: Option<&'static Name>,
pub entity: Entity,
}
impl<'a> core::fmt::Display for NameOrEntityItem<'a> {
#[inline(always)]
fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
match self.name {
Some(name) => core::fmt::Display::fmt(name, f),
None => core::fmt::Display::fmt(&self.entity, f),
}
}
}
impl From<&str> for Name {
#[inline(always)]
fn from(name: &str) -> Self {
Name::new(name.to_owned())
}
}
impl From<String> for Name {
#[inline(always)]
fn from(name: String) -> Self {
Name::new(name)
}
}
impl AsRef<str> for Name {
#[inline(always)]
fn as_ref(&self) -> &str {
&self.name
}
}
impl From<&Name> for String {
#[inline(always)]
fn from(val: &Name) -> String {
val.as_str().to_owned()
}
}
impl From<Name> for String {
#[inline(always)]
fn from(val: Name) -> String {
val.name.into_owned()
}
}
impl Hash for Name {
fn hash<H: Hasher>(&self, state: &mut H) {
self.name.hash(state);
}
}
impl PartialEq for Name {
fn eq(&self, other: &Self) -> bool {
if self.hash != other.hash {
return false;
}
self.name.eq(&other.name)
}
}
impl Eq for Name {}
impl PartialOrd for Name {
fn partial_cmp(&self, other: &Self) -> Option<core::cmp::Ordering> {
Some(self.cmp(other))
}
}
impl Ord for Name {
fn cmp(&self, other: &Self) -> core::cmp::Ordering {
self.name.cmp(&other.name)
}
}
impl Deref for Name {
type Target = str;
fn deref(&self) -> &Self::Target {
self.name.as_ref()
}
}
#[cfg(feature = "serialize")]
impl Serialize for Name {
fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
serializer.serialize_str(self.as_str())
}
}
#[cfg(feature = "serialize")]
impl<'de> Deserialize<'de> for Name {
fn deserialize<D: Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
deserializer.deserialize_str(NameVisitor)
}
}
#[cfg(feature = "serialize")]
struct NameVisitor;
#[cfg(feature = "serialize")]
impl<'de> Visitor<'de> for NameVisitor {
type Value = Name;
fn expecting(&self, formatter: &mut core::fmt::Formatter) -> core::fmt::Result {
formatter.write_str(core::any::type_name::<Name>())
}
fn visit_str<E: Error>(self, v: &str) -> Result<Self::Value, E> {
Ok(Name::new(v.to_string()))
}
fn visit_string<E: Error>(self, v: String) -> Result<Self::Value, E> {
Ok(Name::new(v))
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::world::World;
use alloc::string::ToString;
#[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::<NameOrEntity>();
let d1 = query.get(&world, e1).unwrap();
let d2 = query.get(&world, e2).unwrap();
assert_eq!(d1.to_string(), "0v1");
assert_eq!(d2.to_string(), "MyName");
}
}
#[cfg(all(test, feature = "serialize"))]
mod serde_tests {
use super::Name;
use serde_test::{assert_tokens, Token};
#[test]
fn test_serde_name() {
let name = Name::new("MyComponent");
assert_tokens(&name, &[Token::String("MyComponent")]);
}
}