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}