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}