async_ecs/world/lazy.rs
1use std::sync::Arc;
2
3use crossbeam_queue::SegQueue;
4use futures::future::BoxFuture;
5use log::warn;
6
7use crate::{
8 access::WriteStorage,
9 component::Component,
10 entity::{Builder, Entity},
11 system::SystemData,
12};
13
14use super::World;
15
16/// Lazy updates can be used for world updates that need to borrow a lot of resources
17/// and as such should better be done at the end. They work lazily in the sense that
18/// they are dispatched when calling `world.maintain()`.
19///
20/// Lazy updates are dispatched in the order that they are requested. Multiple updates
21/// sent from one system may be overridden by updates sent from other systems.
22///
23/// Please note that the provided methods take `&self` so there's no need to get
24/// `Lazy` mutably. This resource is added to the world by default.
25pub struct Lazy {
26 queue: Arc<SegQueue<LazyUpdate>>,
27}
28
29impl Lazy {
30 /// Lazily executes a closure with world access.
31 ///
32 /// ## Examples
33 ///
34 /// ```
35 /// # use async_ecs::*;
36 /// #
37 /// struct Pos;
38 ///
39 /// impl Component for Pos {
40 /// type Storage = VecStorage<Self>;
41 /// }
42 ///
43 /// struct Execution;
44 ///
45 /// impl<'a> System<'a> for Execution {
46 /// type SystemData = (Entities<'a>, Read<'a, Lazy>);
47 ///
48 /// fn run(&mut self, (ent, lazy): Self::SystemData) {
49 /// for entity in ent.join() {
50 /// lazy.exec(move |world| {
51 /// if world.is_alive(entity) {
52 /// println!("Entity {:?} is alive.", entity);
53 /// }
54 /// });
55 /// }
56 /// }
57 /// }
58 /// ```
59 pub fn exec<F>(&self, f: F)
60 where
61 F: FnOnce(&mut World) + Send + Sync + 'static,
62 {
63 self.queue.push(LazyUpdate::Sync(Box::new(f)));
64 }
65
66 /// Same as `Lazy::exec` but with async response.
67 pub fn exec_async<F>(&self, f: F)
68 where
69 F: FnOnce(&mut World) -> BoxFuture<'static, ()> + Send + Sync + 'static,
70 {
71 self.queue.push(LazyUpdate::Async(Box::new(f)));
72 }
73
74 /// Lazily inserts a component for an entity.
75 ///
76 /// ## Examples
77 ///
78 /// ```
79 /// # use async_ecs::*;
80 /// #
81 /// struct Pos(f32, f32);
82 ///
83 /// impl Component for Pos {
84 /// type Storage = VecStorage<Self>;
85 /// }
86 ///
87 /// struct InsertPos;
88 ///
89 /// impl<'a> System<'a> for InsertPos {
90 /// type SystemData = (Entities<'a>, Read<'a, Lazy>);
91 ///
92 /// fn run(&mut self, (ent, lazy): Self::SystemData) {
93 /// let a = ent.create();
94 /// lazy.insert(a, Pos(1.0, 1.0));
95 /// }
96 /// }
97 /// ```
98 pub fn insert<C>(&self, e: Entity, c: C)
99 where
100 C: Component + Send + Sync,
101 {
102 self.exec(move |world| {
103 let mut storage: WriteStorage<C> = SystemData::fetch(world);
104
105 if storage.insert(e, c).is_err() {
106 warn!("Lazy insert of component failed because {:?} was dead.", e);
107 }
108 });
109 }
110
111 /// Lazily inserts components for entities.
112 ///
113 /// ## Examples
114 ///
115 /// ```
116 /// # use async_ecs::*;
117 /// #
118 /// struct Pos(f32, f32);
119 ///
120 /// impl Component for Pos {
121 /// type Storage = VecStorage<Self>;
122 /// }
123 ///
124 /// struct InsertPos;
125 ///
126 /// impl<'a> System<'a> for InsertPos {
127 /// type SystemData = (Entities<'a>, Read<'a, Lazy>);
128 ///
129 /// fn run(&mut self, (ent, lazy): Self::SystemData) {
130 /// let a = ent.create();
131 /// let b = ent.create();
132 ///
133 /// lazy.insert_many(vec![(a, Pos(3.0, 1.0)), (b, Pos(0.0, 4.0))]);
134 /// }
135 /// }
136 /// ```
137 pub fn insert_many<C, I>(&self, iter: I)
138 where
139 C: Component + Send + Sync,
140 I: IntoIterator<Item = (Entity, C)> + Send + Sync + 'static,
141 {
142 self.exec(move |world| {
143 let mut storage: WriteStorage<C> = SystemData::fetch(world);
144
145 for (e, c) in iter {
146 if storage.insert(e, c).is_err() {
147 log::warn!("Lazy insert of component failed because {:?} was dead.", e);
148 }
149 }
150 });
151 }
152
153 /// Lazily removes a component.
154 ///
155 /// ## Examples
156 ///
157 /// ```
158 /// # use async_ecs::*;
159 /// #
160 /// struct Pos;
161 ///
162 /// impl Component for Pos {
163 /// type Storage = VecStorage<Self>;
164 /// }
165 ///
166 /// struct RemovePos;
167 ///
168 /// impl<'a> System<'a> for RemovePos {
169 /// type SystemData = (Entities<'a>, Read<'a, Lazy>);
170 ///
171 /// fn run(&mut self, (ent, lazy): Self::SystemData) {
172 /// for entity in ent.join() {
173 /// lazy.remove::<Pos>(entity);
174 /// }
175 /// }
176 /// }
177 /// ```
178 pub fn remove<C>(&self, e: Entity)
179 where
180 C: Component,
181 {
182 self.exec(move |world| {
183 let mut storage: WriteStorage<C> = SystemData::fetch(world);
184
185 storage.remove(e);
186 });
187 }
188
189 /// Lazily removes a component.
190 ///
191 /// ## Examples
192 ///
193 /// ```
194 /// # use async_ecs::*;
195 /// #
196 /// struct Pos;
197 ///
198 /// impl Component for Pos {
199 /// type Storage = VecStorage<Self>;
200 /// }
201 ///
202 /// struct RemovePos;
203 ///
204 /// impl<'a> System<'a> for RemovePos {
205 /// type SystemData = (Entities<'a>, Read<'a, Lazy>);
206 ///
207 /// fn run(&mut self, (ent, lazy): Self::SystemData) {
208 /// for entity in ent.join() {
209 /// lazy.remove::<Pos>(entity);
210 /// }
211 /// }
212 /// }
213 /// ```
214 pub fn remove_many<C, I>(&self, iter: I)
215 where
216 C: Component,
217 I: IntoIterator<Item = Entity> + Send + Sync + 'static,
218 {
219 self.exec(move |world| {
220 let mut storage: WriteStorage<C> = SystemData::fetch(world);
221
222 for e in iter {
223 storage.remove(e);
224 }
225 });
226 }
227
228 /// Creates a new `LazyBuilder` which inserts components
229 /// using `Lazy`. This means that the components won't
230 /// be available immediately, but only after a `maintain`
231 /// on `World` is performed.
232 ///
233 /// ## Examples
234 ///
235 /// ```
236 /// # use async_ecs::*;
237 /// # let mut world = World::default();
238 /// struct Pos(f32, f32);
239 ///
240 /// impl Component for Pos {
241 /// type Storage = VecStorage<Self>;
242 /// }
243 ///
244 /// # let lazy = world.resource::<Lazy>();
245 /// let my_entity = lazy.create_entity(&world).with(Pos(1.0, 3.0)).build();
246 /// ```
247 pub fn create_entity(&self, world: &World) -> LazyBuilder {
248 let entity = world.entities().create();
249
250 LazyBuilder { entity, lazy: self }
251 }
252
253 /// Executes all stored lazy updates
254 pub async fn maintain(&self, world: &mut World) {
255 while let Some(update) = self.queue.pop() {
256 match update {
257 LazyUpdate::Sync(update) => update(world),
258 LazyUpdate::Async(update) => update(world).await,
259 }
260 }
261 }
262}
263
264impl Default for Lazy {
265 fn default() -> Self {
266 Self {
267 queue: Arc::new(SegQueue::new()),
268 }
269 }
270}
271
272impl Clone for Lazy {
273 fn clone(&self) -> Self {
274 Self {
275 queue: self.queue.clone(),
276 }
277 }
278}
279
280enum LazyUpdate {
281 Sync(Box<dyn FnOnce(&mut World) + Send + Sync + 'static>),
282 Async(Box<dyn FnOnce(&mut World) -> BoxFuture<'static, ()> + Send + Sync + 'static>),
283}
284
285/* LazyBuilder */
286
287/// Like `EntityBuilder`, but inserts the component
288/// lazily, meaning on `maintain`.
289/// If you need those components to exist immediately,
290/// you have to insert them into the storages yourself.
291pub struct LazyBuilder<'a> {
292 pub entity: Entity,
293 pub lazy: &'a Lazy,
294}
295
296impl<'a> Builder for LazyBuilder<'a> {
297 /// Inserts a component using [Lazy].
298 ///
299 /// If a component was already associated with the entity, it will
300 /// overwrite the previous component.
301 fn with<C>(self, component: C) -> Self
302 where
303 C: Component + Send + Sync,
304 {
305 let entity = self.entity;
306 self.lazy.exec(move |world| {
307 let mut storage: WriteStorage<C> = SystemData::fetch(world);
308
309 if storage.insert(entity, component).is_err() {
310 warn!(
311 "Lazy insert of component failed because {:?} was dead.",
312 entity
313 );
314 }
315 });
316
317 self
318 }
319
320 /// Finishes the building and returns the built entity.
321 /// Please note that no component is associated to this
322 /// entity until you call [`World::maintain`].
323 fn build(self) -> Entity {
324 self.entity
325 }
326}