specs/world/
mod.rs

1//! Entities, resources, components, and general world management.
2
3pub use shred::World;
4
5pub use self::{
6    comp::Component,
7    entity::{
8        CreateIterAtomic, Entities, EntitiesRes, Entity, EntityResBuilder, Generation, Index,
9    },
10    lazy::{LazyBuilder, LazyUpdate},
11    world_ext::WorldExt,
12};
13
14use shred::{FetchMut, SystemData};
15
16use crate::storage::WriteStorage;
17
18mod comp;
19mod entity;
20mod lazy;
21#[cfg(test)]
22mod tests;
23mod world_ext;
24
25/// An iterator for entity creation.
26/// Please note that you have to consume
27/// it because iterators are lazy.
28///
29/// Returned from `World::create_iter`.
30pub struct CreateIter<'a>(FetchMut<'a, EntitiesRes>);
31
32impl<'a> Iterator for CreateIter<'a> {
33    type Item = Entity;
34
35    fn next(&mut self) -> Option<Entity> {
36        Some(self.0.alloc.allocate())
37    }
38}
39
40/// A common trait for `EntityBuilder` and `LazyBuilder`, allowing either to be
41/// used. Entity is definitely alive, but the components may or may not exist
42/// before a call to `World::maintain`.
43pub trait Builder {
44    /// Appends a component and associates it with the entity.
45    ///
46    /// If a component was already associated with the entity, it should
47    /// overwrite the previous component.
48    ///
49    /// # Panics
50    ///
51    /// Panics if the component hasn't been `register()`ed in the
52    /// `World`.
53    #[cfg(feature = "parallel")]
54    fn with<C: Component + Send + Sync>(self, c: C) -> Self;
55
56    /// Appends a component and associates it with the entity.
57    ///
58    /// If a component was already associated with the entity, it should
59    /// overwrite the previous component.
60    ///
61    /// # Panics
62    ///
63    /// Panics if the component hasn't been `register()`ed in the
64    /// `World`.
65    #[cfg(not(feature = "parallel"))]
66    fn with<C: Component>(self, c: C) -> Self;
67
68    /// Convenience method that calls `self.with(component)` if
69    /// `Some(component)` is provided
70    ///
71    /// # Panics
72    ///
73    /// Panics if the component hasn't been `register()`ed in the
74    /// `World`.
75    #[cfg(feature = "parallel")]
76    fn maybe_with<C: Component + Send + Sync>(self, c: Option<C>) -> Self
77    where
78        Self: Sized,
79    {
80        match c {
81            Some(c) => self.with(c),
82            None => self,
83        }
84    }
85
86    /// Convenience method that calls `self.with(component)` if
87    /// `Some(component)` is provided
88    ///
89    /// # Panics
90    ///
91    /// Panics if the component hasn't been `register()`ed in the
92    /// `World`.
93    #[cfg(not(feature = "parallel"))]
94    fn maybe_with<C: Component>(self, c: Option<C>) -> Self
95    where
96        Self: Sized,
97    {
98        match c {
99            Some(c) => self.with(c),
100            None => self,
101        }
102    }
103
104    /// Finishes the building and returns the entity.
105    fn build(self) -> Entity;
106}
107
108/// The entity builder, allowing to
109/// build an entity together with its components.
110///
111/// ## Examples
112///
113/// ```
114/// use specs::{prelude::*, storage::HashMapStorage};
115///
116/// struct Health(f32);
117///
118/// impl Component for Health {
119///     type Storage = HashMapStorage<Self>;
120/// }
121///
122/// struct Pos {
123///     x: f32,
124///     y: f32,
125/// }
126///
127/// impl Component for Pos {
128///     type Storage = DenseVecStorage<Self>;
129/// }
130///
131/// let mut world = World::new();
132/// world.register::<Health>();
133/// world.register::<Pos>();
134///
135/// let entity = world
136///     .create_entity() // This call returns `EntityBuilder`
137///     .with(Health(4.0))
138///     .with(Pos { x: 1.0, y: 3.0 })
139///     .build(); // Returns the `Entity`
140/// ```
141///
142/// ### Distinguishing Mandatory Components from Optional Components
143///
144/// ```
145/// use specs::{prelude::*, storage::HashMapStorage};
146///
147/// struct MandatoryHealth(f32);
148///
149/// impl Component for MandatoryHealth {
150///     type Storage = HashMapStorage<Self>;
151/// }
152///
153/// struct OptionalPos {
154///     x: f32,
155///     y: f32,
156/// }
157///
158/// impl Component for OptionalPos {
159///     type Storage = DenseVecStorage<Self>;
160/// }
161///
162/// let mut world = World::new();
163/// world.register::<MandatoryHealth>();
164/// world.register::<OptionalPos>();
165///
166/// let mut entitybuilder = world.create_entity().with(MandatoryHealth(4.0));
167///
168/// // something trivial to serve as our conditional
169/// let include_optional = true;
170///
171/// if include_optional == true {
172///     entitybuilder = entitybuilder.with(OptionalPos { x: 1.0, y: 3.0 })
173/// }
174///
175/// let entity = entitybuilder.build();
176/// ```
177#[must_use = "Please call .build() on this to finish building it."]
178pub struct EntityBuilder<'a> {
179    /// The (already created) entity for which components will be inserted.
180    pub entity: Entity,
181    /// A reference to the `World` for component insertions.
182    pub world: &'a World,
183    built: bool,
184}
185
186impl<'a> Builder for EntityBuilder<'a> {
187    /// Inserts a component for this entity.
188    ///
189    /// If a component was already associated with the entity, it will
190    /// overwrite the previous component.
191    #[inline]
192    fn with<T: Component>(self, c: T) -> Self {
193        {
194            let mut storage: WriteStorage<T> = SystemData::fetch(self.world);
195            // This can't fail.  This is guaranteed by the lifetime 'a
196            // in the EntityBuilder.
197            storage.insert(self.entity, c).unwrap();
198        }
199
200        self
201    }
202
203    /// Finishes the building and returns the entity. As opposed to
204    /// `LazyBuilder`, the components are available immediately.
205    #[inline]
206    fn build(mut self) -> Entity {
207        self.built = true;
208        self.entity
209    }
210}
211
212impl<'a> Drop for EntityBuilder<'a> {
213    fn drop(&mut self) {
214        if !self.built {
215            self.world
216                .read_resource::<EntitiesRes>()
217                .delete(self.entity)
218                .unwrap();
219        }
220    }
221}