specs/world/
lazy.rs

1use crossbeam_queue::SegQueue;
2
3use crate::{prelude::*, world::EntitiesRes};
4use std::sync::Arc;
5
6struct Queue<T>(SegQueue<T>);
7
8impl<T> Default for Queue<T> {
9    fn default() -> Self {
10        Self(SegQueue::default())
11    }
12}
13
14#[cfg(feature = "parallel")]
15pub trait LazyUpdateInternal: Send + Sync {
16    fn update(self: Box<Self>, world: &mut World);
17}
18
19#[cfg(not(feature = "parallel"))]
20pub trait LazyUpdateInternal {
21    fn update(self: Box<Self>, world: &mut World);
22}
23
24/// Generates two versions of functions within the macro call:
25///
26/// * One with `Send + Sync` bounds when the `"parallel"` feature is enabled.
27/// * One without `Send + Sync` bounds when the `"parallel"` feature is
28///   disabled.
29///
30/// TODO: When trait aliases land on stable we can remove this macro.
31/// See <https://github.com/rust-lang/rust/issues/41517>.
32///
33/// ```rust,ignore
34/// #![cfg(feature = "parallel")]
35/// trait ComponentBound = Component + Send + Sync;
36/// #![cfg(not(feature = "parallel"))]
37/// trait ComponentBound = Component;
38/// ```
39///
40/// Alternative solutions are listed in:
41/// <https://github.com/amethyst/specs/pull/674#issuecomment-585013726>
42macro_rules! parallel_feature {
43    (
44        $(
45            $(#[$attrs:meta])* $($words:ident)+<$($ty_params:ident),+> $args:tt $(-> $return_ty:ty)?
46            where
47                $($ty_param:ident:
48                    $bound_first:ident $(< $ty_type:ident = $ty_bound:tt >)? $(($($fn_bound:tt)*))?
49                    $(+ $bound:tt $($bound_2:ident)?)*,)+
50            $body:block
51        )+
52    ) =>
53    {
54        $(
55            $(#[$attrs])*
56            #[cfg(feature = "parallel")]
57            $($words)+<$($ty_params),+> $args $(-> $return_ty)?
58            where
59                $($ty_param:
60                    Send + Sync +
61                    $bound_first $(< $ty_type = $ty_bound >)? $(($($fn_bound)*))?
62                    $(+ $bound $($bound_2)?)*,)+
63            $body
64
65            $(#[$attrs])*
66            #[cfg(not(feature = "parallel"))]
67            $($words)+<$($ty_params),+> $args $(-> $return_ty)?
68            where
69                $($ty_param:
70                    $bound_first $(< $ty_type = $ty_bound >)? $(($($fn_bound)*))?
71                    $(+ $bound $($bound_2)?)*,)+
72            $body
73        )+
74    };
75}
76
77/// Like `EntityBuilder`, but inserts the component
78/// lazily, meaning on `maintain`.
79/// If you need those components to exist immediately,
80/// you have to insert them into the storages yourself.
81#[must_use = "Please call .build() on this to finish building it."]
82pub struct LazyBuilder<'a> {
83    /// The entity that we're inserting components for.
84    pub entity: Entity,
85    /// The lazy update reference.
86    pub lazy: &'a LazyUpdate,
87}
88
89impl<'a> Builder for LazyBuilder<'a> {
90    parallel_feature! {
91        /// Inserts a component using [LazyUpdate].
92        ///
93        /// If a component was already associated with the entity, it will
94        /// overwrite the previous component.
95        fn with<C>(self, component: C) -> Self
96        where
97            C: Component,
98        {
99            let entity = self.entity;
100            self.lazy.exec(move |world| {
101                let mut storage: WriteStorage<C> = SystemData::fetch(world);
102                if storage.insert(entity, component).is_err() {
103                    log::warn!(
104                        "Lazy insert of component failed because {:?} was dead.",
105                        entity
106                    );
107                }
108            });
109
110            self
111        }
112    }
113
114    /// Finishes the building and returns the built entity.
115    /// Please note that no component is associated to this
116    /// entity until you call [`World::maintain`].
117    fn build(self) -> Entity {
118        self.entity
119    }
120}
121
122#[cfg(feature = "parallel")]
123impl<F> LazyUpdateInternal for F
124where
125    F: FnOnce(&mut World) + Send + Sync + 'static,
126{
127    fn update(self: Box<Self>, world: &mut World) {
128        self(world);
129    }
130}
131
132#[cfg(not(feature = "parallel"))]
133impl<F> LazyUpdateInternal for F
134where
135    F: FnOnce(&mut World) + 'static,
136{
137    fn update(self: Box<Self>, world: &mut World) {
138        self(world);
139    }
140}
141
142/// Lazy updates can be used for world updates
143/// that need to borrow a lot of resources
144/// and as such should better be done at the end.
145/// They work lazily in the sense that they are
146/// dispatched when calling `world.maintain()`.
147///
148/// Lazy updates are dispatched in the order that they
149/// are requested. Multiple updates sent from one system
150/// may be overridden by updates sent from other systems.
151///
152/// Please note that the provided methods take `&self`
153/// so there's no need to get `LazyUpdate` mutably.
154/// This resource is added to the world by default.
155#[derive(Default)]
156pub struct LazyUpdate {
157    queue: Arc<Queue<Box<dyn LazyUpdateInternal>>>,
158}
159
160impl LazyUpdate {
161    parallel_feature! {
162        /// Lazily inserts a component for an entity.
163        ///
164        /// ## Examples
165        ///
166        /// ```
167        /// # use specs::prelude::*;
168        /// #
169        /// struct Pos(f32, f32);
170        ///
171        /// impl Component for Pos {
172        ///     type Storage = VecStorage<Self>;
173        /// }
174        ///
175        /// struct InsertPos;
176        ///
177        /// impl<'a> System<'a> for InsertPos {
178        ///     type SystemData = (Entities<'a>, Read<'a, LazyUpdate>);
179        ///
180        ///     fn run(&mut self, (ent, lazy): Self::SystemData) {
181        ///         let a = ent.create();
182        ///         lazy.insert(a, Pos(1.0, 1.0));
183        ///     }
184        /// }
185        /// ```
186        pub fn insert<C>(&self, e: Entity, c: C)
187        where
188            C: Component,
189        {
190            self.exec(move |world| {
191                let mut storage: WriteStorage<C> = SystemData::fetch(world);
192                if storage.insert(e, c).is_err() {
193                    log::warn!("Lazy insert of component failed because {:?} was dead.", e);
194                }
195            });
196        }
197
198        /// Lazily inserts components for entities.
199        ///
200        /// ## Examples
201        ///
202        /// ```
203        /// # use specs::prelude::*;
204        /// #
205        /// struct Pos(f32, f32);
206        ///
207        /// impl Component for Pos {
208        ///     type Storage = VecStorage<Self>;
209        /// }
210        ///
211        /// struct InsertPos;
212        ///
213        /// impl<'a> System<'a> for InsertPos {
214        ///     type SystemData = (Entities<'a>, Read<'a, LazyUpdate>);
215        ///
216        ///     fn run(&mut self, (ent, lazy): Self::SystemData) {
217        ///         let a = ent.create();
218        ///         let b = ent.create();
219        ///
220        ///         lazy.insert_all(vec![(a, Pos(3.0, 1.0)), (b, Pos(0.0, 4.0))]);
221        ///     }
222        /// }
223        /// ```
224        pub fn insert_all<C, I>(&self, iter: I)
225        where
226            C: Component,
227            I: IntoIterator<Item = (Entity, C)> + 'static,
228        {
229            self.exec(move |world| {
230                let mut storage: WriteStorage<C> = SystemData::fetch(world);
231                for (e, c) in iter {
232                    if storage.insert(e, c).is_err() {
233                        log::warn!("Lazy insert of component failed because {:?} was dead.", e);
234                    }
235                }
236            });
237        }
238
239        /// Lazily removes a component.
240        ///
241        /// ## Examples
242        ///
243        /// ```
244        /// # use specs::prelude::*;
245        /// #
246        /// struct Pos;
247        ///
248        /// impl Component for Pos {
249        ///     type Storage = VecStorage<Self>;
250        /// }
251        ///
252        /// struct RemovePos;
253        ///
254        /// impl<'a> System<'a> for RemovePos {
255        ///     type SystemData = (Entities<'a>, Read<'a, LazyUpdate>);
256        ///
257        ///     fn run(&mut self, (ent, lazy): Self::SystemData) {
258        ///         for entity in ent.join() {
259        ///             lazy.remove::<Pos>(entity);
260        ///         }
261        ///     }
262        /// }
263        /// ```
264        pub fn remove<C>(&self, e: Entity)
265        where
266            C: Component,
267        {
268            self.exec(move |world| {
269                let mut storage: WriteStorage<C> = SystemData::fetch(world);
270                storage.remove(e);
271            });
272        }
273
274        /// Lazily executes a closure with world access.
275        ///
276        /// ## Examples
277        ///
278        /// ```
279        /// # use specs::prelude::*;
280        /// #
281        /// struct Pos;
282        ///
283        /// impl Component for Pos {
284        ///     type Storage = VecStorage<Self>;
285        /// }
286        ///
287        /// struct Execution;
288        ///
289        /// impl<'a> System<'a> for Execution {
290        ///     type SystemData = (Entities<'a>, Read<'a, LazyUpdate>);
291        ///
292        ///     fn run(&mut self, (ent, lazy): Self::SystemData) {
293        ///         for entity in ent.join() {
294        ///             lazy.exec(move |world| {
295        ///                 if world.is_alive(entity) {
296        ///                     println!("Entity {:?} is alive.", entity);
297        ///                 }
298        ///             });
299        ///         }
300        ///     }
301        /// }
302        /// ```
303        pub fn exec<F>(&self, f: F)
304        where
305            F: FnOnce(&mut World) + 'static,
306        {
307            self.queue
308                .0
309                .push(Box::new(f));
310        }
311
312        /// Lazily executes a closure with mutable world access.
313        ///
314        /// This can be used to add a resource to the `World` from a system.
315        ///
316        /// ## Examples
317        ///
318        /// ```
319        /// # use specs::prelude::*;
320        /// #
321        ///
322        /// struct Sys;
323        ///
324        /// impl<'a> System<'a> for Sys {
325        ///     type SystemData = (Entities<'a>, Read<'a, LazyUpdate>);
326        ///
327        ///     fn run(&mut self, (ent, lazy): Self::SystemData) {
328        ///         for entity in ent.join() {
329        ///             lazy.exec_mut(move |world| {
330        ///                 // complete extermination!
331        ///                 world.delete_all();
332        ///             });
333        ///         }
334        ///     }
335        /// }
336        /// ```
337        pub fn exec_mut<F>(&self, f: F)
338        where
339            F: FnOnce(&mut World) + 'static,
340        {
341            self.queue.0.push(Box::new(f));
342        }
343    }
344
345    /// Creates a new `LazyBuilder` which inserts components
346    /// using `LazyUpdate`. This means that the components won't
347    /// be available immediately, but only after a `maintain`
348    /// on `World` is performed.
349    ///
350    /// ## Examples
351    ///
352    /// ```
353    /// # use specs::prelude::*;
354    /// # let mut world = World::new();
355    /// struct Pos(f32, f32);
356    ///
357    /// impl Component for Pos {
358    ///     type Storage = VecStorage<Self>;
359    /// }
360    ///
361    /// # let lazy = world.read_resource::<LazyUpdate>();
362    /// # let entities = world.entities();
363    /// let my_entity = lazy.create_entity(&entities).with(Pos(1.0, 3.0)).build();
364    /// ```
365    pub fn create_entity(&self, ent: &EntitiesRes) -> LazyBuilder {
366        let entity = ent.create();
367
368        LazyBuilder { entity, lazy: self }
369    }
370
371    pub(super) fn clone(&self) -> Self {
372        Self {
373            queue: self.queue.clone(),
374        }
375    }
376
377    pub(super) fn maintain(&self, world: &mut World) {
378        while let Some(l) = self.queue.0.pop() {
379            l.update(world);
380        }
381    }
382}
383
384impl Drop for LazyUpdate {
385    fn drop(&mut self) {
386        // TODO: remove as soon as leak is fixed in crossbeam
387        while self.queue.0.pop().is_some() {}
388    }
389}