async_ecs/entity/builder.rs
1use crate::{access::WriteStorage, component::Component, system::SystemData, world::World};
2
3use super::Entity;
4
5/// A common trait for `EntityBuilder` and `LazyBuilder`, allowing either to be
6/// used. Entity is definitely alive, but the components may or may not exist
7/// before a call to `World::maintain`.
8pub trait Builder {
9 /// Appends a component and associates it with the entity.
10 ///
11 /// If a component was already associated with the entity, it should
12 /// overwrite the previous component.
13 ///
14 /// # Panics
15 ///
16 /// Panics if the component hasn't been `register()`ed in the
17 /// `World`.
18 fn with<C: Component + Send + Sync>(self, component: C) -> Self;
19
20 /// Finishes the building and returns the entity.
21 fn build(self) -> Entity;
22}
23
24/// The entity builder, allowing to
25/// build an entity together with its components.
26///
27/// ## Examples
28///
29/// ```
30/// use async_ecs::*;
31///
32/// struct Health(f32);
33///
34/// impl Component for Health {
35/// type Storage = HashMapStorage<Self>;
36/// }
37///
38/// struct Pos {
39/// x: f32,
40/// y: f32,
41/// }
42///
43/// impl Component for Pos {
44/// type Storage = DenseVecStorage<Self>;
45/// }
46///
47/// let mut world = World::default();
48/// world.register_component::<Health>();
49/// world.register_component::<Pos>();
50///
51/// let entity = world
52/// .create_entity() // This call returns `EntityBuilder`
53/// .with(Health(4.0))
54/// .with(Pos { x: 1.0, y: 3.0 })
55/// .build(); // Returns the `Entity`
56/// ```
57///
58/// ### Distinguishing Mandatory Components from Optional Components
59///
60/// ```
61/// use async_ecs::*;
62///
63/// struct MandatoryHealth(f32);
64///
65/// impl Component for MandatoryHealth {
66/// type Storage = HashMapStorage<Self>;
67/// }
68///
69/// struct OptionalPos {
70/// x: f32,
71/// y: f32,
72/// }
73///
74/// impl Component for OptionalPos {
75/// type Storage = DenseVecStorage<Self>;
76/// }
77///
78/// let mut world = World::default();
79/// world.register_component::<MandatoryHealth>();
80/// world.register_component::<OptionalPos>();
81///
82/// let mut entitybuilder = world.create_entity().with(MandatoryHealth(4.0));
83///
84/// // something trivial to serve as our conditional
85/// let include_optional = true;
86///
87/// if include_optional == true {
88/// entitybuilder = entitybuilder.with(OptionalPos { x: 1.0, y: 3.0 })
89/// }
90///
91/// let entity = entitybuilder.build();
92/// ```
93pub struct EntityBuilder<'a> {
94 world: &'a World,
95 entity: Entity,
96 built: bool,
97}
98
99impl<'a> EntityBuilder<'a> {
100 /// Create new entity builder.
101 pub fn new(world: &'a World) -> Self {
102 let entity = world.entities_mut().allocate();
103
104 Self {
105 world,
106 entity,
107 built: false,
108 }
109 }
110}
111
112impl<'a> Builder for EntityBuilder<'a> {
113 /// Inserts a component for this entity.
114 ///
115 /// If a component was already associated with the entity, it will
116 /// overwrite the previous component.
117 #[inline]
118 fn with<T: Component>(self, c: T) -> Self {
119 {
120 let mut storage = WriteStorage::<T>::fetch(&self.world);
121
122 storage.insert(self.entity, c).unwrap();
123 }
124
125 self
126 }
127
128 /// Finishes the building and returns the entity. As opposed to
129 /// `LazyBuilder`, the components are available immediately.
130 #[inline]
131 fn build(mut self) -> Entity {
132 self.built = true;
133
134 self.entity
135 }
136}
137
138impl Drop for EntityBuilder<'_> {
139 fn drop(&mut self) {
140 if !self.built {
141 self.world.entities_mut().delete(self.entity).unwrap();
142 }
143 }
144}