1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
use std::borrow::Cow;

use crate::ecs::{world::LazyBuilder, Component, DenseVecStorage, EntityBuilder, WriteStorage};
use serde::{Deserialize, Serialize};

/// A component that gives a name to an [`Entity`].
///
/// There are two ways you can get a name for an entity:
///
/// * Hard-coding the entity name in code, in which case the name would be a [`&'static str`][str].
/// * Dynamically generating the string or loading it from a data file, in which case the name
///   would be a `String`.
///
/// To support both of these cases smoothly, `Named` stores the name as [`Cow<'static, str>`].
/// You can pass either a [`&'static str`][str] or a [`String`] to [`Named::new`], and your code
/// can generally treat the `name` field as a [`&str`][str] without needing to know whether the
/// name is actually an owned or borrowed string.
///
/// [`Entity`]: https://docs.rs/specs/*/specs/struct.Entity.html
/// [`Cow<'static, str>`]: https://doc.rust-lang.org/std/borrow/enum.Cow.html
/// [`String`]: https://doc.rust-lang.org/std/string/struct.String.html
/// [str]: https://doc.rust-lang.org/std/primitive.str.html
/// [`Named::new`]: #method.new
///
/// # Examples
///
/// Creating a name from string constant:
///
/// ```
/// use amethyst::core::{Named, WithNamed};
/// use amethyst::ecs::prelude::*;
///
/// let mut world = World::new();
/// world.register::<Named>();
///
/// world
///     .create_entity()
///     .named("Super Cool Entity")
///     .build();
/// ```
///
/// Creating a name from a dynamically generated string:
///
/// ```
/// use amethyst::core::{Named, WithNamed};
/// use amethyst::ecs::prelude::*;
///
/// let mut world = World::new();
/// world.register::<Named>();
///
/// for entity_num in 0..10 {
///     world
///         .create_entity()
///         .named(format!("Entity Number {}", entity_num))
///         .build();
/// }
/// ```
///
/// Accessing a named entity in a system:
///
/// ```
/// use amethyst::core::Named;
/// use amethyst::ecs::prelude::*;
///
/// pub struct NameSystem;
///
/// impl<'s> System<'s> for NameSystem {
///     type SystemData = (
///         Entities<'s>,
///         ReadStorage<'s, Named>,
///     );
///
///     fn run(&mut self, (entities, names): Self::SystemData) {
///         for (entity, name) in (&*entities, &names).join() {
///             println!("Entity {:?} is named {}", entity, name.name);
///         }
///     }
/// }
/// ```
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct Named {
    /// The name of the entity this component is attached to.
    pub name: Cow<'static, str>,
}

impl Named {
    /// Constructs a new `Named` from a string.
    ///
    /// # Examples
    ///
    /// From a string constant:
    ///
    /// ```
    /// use amethyst::core::Named;
    ///
    /// let name_component = Named::new("Super Cool Entity");
    /// ```
    ///
    /// From a dynamic string:
    ///
    /// ```
    /// use amethyst::core::Named;
    ///
    /// let entity_num = 7;
    /// let name_component = Named::new(format!("Entity Number {}", entity_num));
    /// ```
    pub fn new<S>(name: S) -> Self
    where
        S: Into<Cow<'static, str>>,
    {
        Named { name: name.into() }
    }
}

impl Component for Named {
    type Storage = DenseVecStorage<Self>;
}

/// An easy way to name an `Entity` and give it a `Named` `Component`.
pub trait WithNamed
where
    Self: Sized,
{
    /// Adds a name to the entity being built.
    fn named<S>(self, name: S) -> Self
    where
        S: Into<Cow<'static, str>>;
}

impl<'a> WithNamed for EntityBuilder<'a> {
    fn named<S>(self, name: S) -> Self
    where
        S: Into<Cow<'static, str>>,
    {
        self.world
            .system_data::<(WriteStorage<'a, Named>,)>()
            .0
            .insert(self.entity, Named::new(name))
            .expect("Unreachable: Entities should always be valid when just created");
        self
    }
}

impl<'a> WithNamed for LazyBuilder<'a> {
    fn named<S>(self, name: S) -> Self
    where
        S: Into<Cow<'static, str>>,
    {
        self.lazy.insert::<Named>(self.entity, Named::new(name));
        self
    }
}