Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
bevyengine
GitHub Repository: bevyengine/bevy
Path: blob/main/crates/bevy_ecs/src/spawn.rs
6849 views
1
//! Entity spawning abstractions, largely focused on spawning related hierarchies of entities. See [`related`](crate::related) and [`SpawnRelated`]
2
//! for the best entry points into these APIs and examples of how to use them.
3
4
use crate::{
5
bundle::{Bundle, DynamicBundle, InsertMode, NoBundleEffect},
6
change_detection::MaybeLocation,
7
entity::Entity,
8
relationship::{RelatedSpawner, Relationship, RelationshipHookMode, RelationshipTarget},
9
world::{EntityWorldMut, World},
10
};
11
use alloc::vec::Vec;
12
use bevy_ptr::{move_as_ptr, MovingPtr};
13
use core::{
14
marker::PhantomData,
15
mem::{self, MaybeUninit},
16
};
17
use variadics_please::all_tuples_enumerated;
18
19
/// A wrapper over a [`Bundle`] indicating that an entity should be spawned with that [`Bundle`].
20
/// This is intended to be used for hierarchical spawning via traits like [`SpawnableList`] and [`SpawnRelated`].
21
///
22
/// Also see the [`children`](crate::children) and [`related`](crate::related) macros that abstract over the [`Spawn`] API.
23
///
24
/// ```
25
/// # use bevy_ecs::hierarchy::Children;
26
/// # use bevy_ecs::spawn::{Spawn, SpawnRelated};
27
/// # use bevy_ecs::name::Name;
28
/// # use bevy_ecs::world::World;
29
/// let mut world = World::new();
30
/// world.spawn((
31
/// Name::new("Root"),
32
/// Children::spawn((
33
/// Spawn(Name::new("Child1")),
34
/// Spawn((
35
/// Name::new("Child2"),
36
/// Children::spawn(Spawn(Name::new("Grandchild"))),
37
/// ))
38
/// )),
39
/// ));
40
/// ```
41
pub struct Spawn<B: Bundle>(pub B);
42
43
/// A spawn-able list of changes to a given [`World`] and relative to a given [`Entity`]. This is generally used
44
/// for spawning "related" entities, such as children.
45
pub trait SpawnableList<R>: Sized {
46
/// Spawn this list of changes in a given [`World`] and relative to a given [`Entity`]. This is generally used
47
/// for spawning "related" entities, such as children.
48
// This function explicitly uses `MovingPtr` to avoid potentially large stack copies of the bundle
49
// when inserting into ECS storage. See https://github.com/bevyengine/bevy/issues/20571 for more
50
// information.
51
fn spawn(this: MovingPtr<'_, Self>, world: &mut World, entity: Entity);
52
53
/// Returns a size hint, which is used to reserve space for this list in a [`RelationshipTarget`]. This should be
54
/// less than or equal to the actual size of the list. When in doubt, just use 0.
55
fn size_hint(&self) -> usize;
56
}
57
58
impl<R: Relationship, B: Bundle<Effect: NoBundleEffect>> SpawnableList<R> for Vec<B> {
59
fn spawn(ptr: MovingPtr<'_, Self>, world: &mut World, entity: Entity) {
60
let mapped_bundles = ptr.read().into_iter().map(|b| (R::from(entity), b));
61
world.spawn_batch(mapped_bundles);
62
}
63
64
fn size_hint(&self) -> usize {
65
self.len()
66
}
67
}
68
69
impl<R: Relationship, B: Bundle> SpawnableList<R> for Spawn<B> {
70
fn spawn(this: MovingPtr<'_, Self>, world: &mut World, entity: Entity) {
71
#[track_caller]
72
fn spawn<B: Bundle, R: Relationship>(
73
this: MovingPtr<'_, Spawn<B>>,
74
world: &mut World,
75
entity: Entity,
76
) {
77
let caller = MaybeLocation::caller();
78
79
bevy_ptr::deconstruct_moving_ptr!({
80
let Spawn { 0: bundle } = this;
81
});
82
83
let r = R::from(entity);
84
move_as_ptr!(r);
85
let mut entity = world.spawn_with_caller(r, caller);
86
87
entity.insert_with_caller(
88
bundle,
89
InsertMode::Replace,
90
caller,
91
RelationshipHookMode::Run,
92
);
93
}
94
95
spawn::<B, R>(this, world, entity);
96
}
97
98
fn size_hint(&self) -> usize {
99
1
100
}
101
}
102
103
/// A [`SpawnableList`] that spawns entities using an iterator of a given [`Bundle`]:
104
///
105
/// ```
106
/// # use bevy_ecs::hierarchy::Children;
107
/// # use bevy_ecs::spawn::{Spawn, SpawnIter, SpawnRelated};
108
/// # use bevy_ecs::name::Name;
109
/// # use bevy_ecs::world::World;
110
/// let mut world = World::new();
111
/// world.spawn((
112
/// Name::new("Root"),
113
/// Children::spawn((
114
/// Spawn(Name::new("Child1")),
115
/// SpawnIter(["Child2", "Child3"].into_iter().map(Name::new)),
116
/// )),
117
/// ));
118
/// ```
119
pub struct SpawnIter<I>(pub I);
120
121
impl<R: Relationship, I: Iterator<Item = B> + Send + Sync + 'static, B: Bundle> SpawnableList<R>
122
for SpawnIter<I>
123
{
124
fn spawn(mut this: MovingPtr<'_, Self>, world: &mut World, entity: Entity) {
125
for bundle in &mut this.0 {
126
world.spawn((R::from(entity), bundle));
127
}
128
}
129
130
fn size_hint(&self) -> usize {
131
self.0.size_hint().0
132
}
133
}
134
135
/// A [`SpawnableList`] that spawns entities using a [`FnOnce`] with a [`RelatedSpawner`] as an argument:
136
///
137
/// ```
138
/// # use bevy_ecs::hierarchy::{Children, ChildOf};
139
/// # use bevy_ecs::spawn::{Spawn, SpawnWith, SpawnRelated};
140
/// # use bevy_ecs::name::Name;
141
/// # use bevy_ecs::relationship::RelatedSpawner;
142
/// # use bevy_ecs::world::World;
143
/// let mut world = World::new();
144
/// world.spawn((
145
/// Name::new("Root"),
146
/// Children::spawn((
147
/// Spawn(Name::new("Child1")),
148
/// SpawnWith(|parent: &mut RelatedSpawner<ChildOf>| {
149
/// parent.spawn(Name::new("Child2"));
150
/// parent.spawn(Name::new("Child3"));
151
/// }),
152
/// )),
153
/// ));
154
/// ```
155
pub struct SpawnWith<F>(pub F);
156
157
impl<R: Relationship, F: FnOnce(&mut RelatedSpawner<R>) + Send + Sync + 'static> SpawnableList<R>
158
for SpawnWith<F>
159
{
160
fn spawn(this: MovingPtr<'_, Self>, world: &mut World, entity: Entity) {
161
world
162
.entity_mut(entity)
163
.with_related_entities(this.read().0);
164
}
165
166
fn size_hint(&self) -> usize {
167
1
168
}
169
}
170
171
/// A [`SpawnableList`] that links already spawned entities to the root entity via relations of type `I`.
172
///
173
/// This is useful if the entity has already been spawned earlier or if you spawn multiple relationships link to the same entity at the same time.
174
/// If you only need to do this for a single entity, consider using [`WithOneRelated`].
175
///
176
/// ```
177
/// # use bevy_ecs::hierarchy::Children;
178
/// # use bevy_ecs::spawn::{Spawn, WithRelated, SpawnRelated};
179
/// # use bevy_ecs::name::Name;
180
/// # use bevy_ecs::world::World;
181
/// let mut world = World::new();
182
///
183
/// let child2 = world.spawn(Name::new("Child2")).id();
184
/// let child3 = world.spawn(Name::new("Child3")).id();
185
///
186
/// world.spawn((
187
/// Name::new("Root"),
188
/// Children::spawn((
189
/// Spawn(Name::new("Child1")),
190
/// // This adds the already existing entities as children of Root.
191
/// WithRelated::new([child2, child3]),
192
/// )),
193
/// ));
194
/// ```
195
pub struct WithRelated<I>(pub I);
196
197
impl<I> WithRelated<I> {
198
/// Creates a new [`WithRelated`] from a collection of entities.
199
pub fn new(iter: impl IntoIterator<IntoIter = I>) -> Self {
200
Self(iter.into_iter())
201
}
202
}
203
204
impl<R: Relationship, I: Iterator<Item = Entity>> SpawnableList<R> for WithRelated<I> {
205
fn spawn(mut this: MovingPtr<'_, Self>, world: &mut World, entity: Entity) {
206
let related = (&mut this.0).collect::<Vec<_>>();
207
world.entity_mut(entity).add_related::<R>(&related);
208
}
209
210
fn size_hint(&self) -> usize {
211
self.0.size_hint().0
212
}
213
}
214
215
/// A wrapper over an [`Entity`] indicating that an entity should be added.
216
/// This is intended to be used for hierarchical spawning via traits like [`SpawnableList`] and [`SpawnRelated`].
217
///
218
/// Unlike [`WithRelated`] this only adds one entity.
219
///
220
/// Also see the [`children`](crate::children) and [`related`](crate::related) macros that abstract over the [`Spawn`] API.
221
///
222
/// ```
223
/// # use bevy_ecs::hierarchy::Children;
224
/// # use bevy_ecs::spawn::{Spawn, WithOneRelated, SpawnRelated};
225
/// # use bevy_ecs::name::Name;
226
/// # use bevy_ecs::world::World;
227
/// let mut world = World::new();
228
///
229
/// let child1 = world.spawn(Name::new("Child1")).id();
230
///
231
/// world.spawn((
232
/// Name::new("Root"),
233
/// Children::spawn((
234
/// // This adds the already existing entity as a child of Root.
235
/// WithOneRelated(child1),
236
/// )),
237
/// ));
238
/// ```
239
pub struct WithOneRelated(pub Entity);
240
241
impl<R: Relationship> SpawnableList<R> for WithOneRelated {
242
fn spawn(this: MovingPtr<'_, Self>, world: &mut World, entity: Entity) {
243
world.entity_mut(entity).add_one_related::<R>(this.read().0);
244
}
245
246
fn size_hint(&self) -> usize {
247
1
248
}
249
}
250
251
macro_rules! spawnable_list_impl {
252
($(#[$meta:meta])* $(($index:tt, $list: ident, $alias: ident)),*) => {
253
$(#[$meta])*
254
impl<R: Relationship, $($list: SpawnableList<R>),*> SpawnableList<R> for ($($list,)*) {
255
#[expect(
256
clippy::allow_attributes,
257
reason = "This is a tuple-related macro; as such, the lints below may not always apply."
258
)]
259
#[allow(unused_unsafe, reason = "The empty tuple will leave the unsafe blocks unused.")]
260
fn spawn(_this: MovingPtr<'_, Self>, _world: &mut World, _entity: Entity)
261
where
262
Self: Sized,
263
{
264
bevy_ptr::deconstruct_moving_ptr!({
265
let tuple { $($index: $alias),* } = _this;
266
});
267
$( SpawnableList::<R>::spawn($alias, _world, _entity); )*
268
}
269
270
fn size_hint(&self) -> usize {
271
let ($($alias,)*) = self;
272
0 $(+ $alias.size_hint())*
273
}
274
}
275
}
276
}
277
278
all_tuples_enumerated!(
279
#[doc(fake_variadic)]
280
spawnable_list_impl,
281
0,
282
12,
283
P,
284
field_
285
);
286
287
/// A [`Bundle`] that:
288
/// 1. Contains a [`RelationshipTarget`] component (associated with the given [`Relationship`]). This reserves space for the [`SpawnableList`].
289
/// 2. Spawns a [`SpawnableList`] of related entities with a given [`Relationship`].
290
///
291
/// This is intended to be created using [`SpawnRelated`].
292
pub struct SpawnRelatedBundle<R: Relationship, L: SpawnableList<R>> {
293
list: L,
294
marker: PhantomData<R>,
295
}
296
297
// SAFETY: This internally relies on the RelationshipTarget's Bundle implementation, which is sound.
298
unsafe impl<R: Relationship, L: SpawnableList<R> + Send + Sync + 'static> Bundle
299
for SpawnRelatedBundle<R, L>
300
{
301
fn component_ids(
302
components: &mut crate::component::ComponentsRegistrator,
303
ids: &mut impl FnMut(crate::component::ComponentId),
304
) {
305
<R::RelationshipTarget as Bundle>::component_ids(components, ids);
306
}
307
308
fn get_component_ids(
309
components: &crate::component::Components,
310
ids: &mut impl FnMut(Option<crate::component::ComponentId>),
311
) {
312
<R::RelationshipTarget as Bundle>::get_component_ids(components, ids);
313
}
314
}
315
316
impl<R: Relationship, L: SpawnableList<R>> DynamicBundle for SpawnRelatedBundle<R, L> {
317
type Effect = Self;
318
319
unsafe fn get_components(
320
ptr: MovingPtr<'_, Self>,
321
func: &mut impl FnMut(crate::component::StorageType, bevy_ptr::OwningPtr<'_>),
322
) {
323
let target =
324
<R::RelationshipTarget as RelationshipTarget>::with_capacity(ptr.list.size_hint());
325
move_as_ptr!(target);
326
// SAFETY:
327
// - The caller must ensure that this is called exactly once before `apply_effect`.
328
// - Assuming `DynamicBundle` is implemented correctly for `R::Relationship` target, `func` should be
329
// called exactly once for each component being fetched with the correct `StorageType`
330
// - `Effect: !NoBundleEffect`, which means the caller is responsible for calling this type's `apply_effect`
331
// at least once before returning to safe code.
332
<R::RelationshipTarget as DynamicBundle>::get_components(target, func);
333
// Forget the pointer so that the value is available in `apply_effect`.
334
mem::forget(ptr);
335
}
336
337
unsafe fn apply_effect(ptr: MovingPtr<'_, MaybeUninit<Self>>, entity: &mut EntityWorldMut) {
338
// SAFETY: The value was not moved out in `get_components`, only borrowed, and thus should still
339
// be valid and initialized.
340
let effect = unsafe { ptr.assume_init() };
341
let id = entity.id();
342
343
entity.world_scope(|world: &mut World| {
344
bevy_ptr::deconstruct_moving_ptr!({
345
let Self { list, marker: _ } = effect;
346
});
347
L::spawn(list, world, id);
348
});
349
}
350
}
351
352
/// A [`Bundle`] that:
353
/// 1. Contains a [`RelationshipTarget`] component (associated with the given [`Relationship`]). This reserves space for a single entity.
354
/// 2. Spawns a single related entity containing the given `B` [`Bundle`] and the given [`Relationship`].
355
///
356
/// This is intended to be created using [`SpawnRelated`].
357
pub struct SpawnOneRelated<R: Relationship, B: Bundle> {
358
bundle: B,
359
marker: PhantomData<R>,
360
}
361
362
impl<R: Relationship, B: Bundle> DynamicBundle for SpawnOneRelated<R, B> {
363
type Effect = Self;
364
365
unsafe fn get_components(
366
ptr: MovingPtr<'_, Self>,
367
func: &mut impl FnMut(crate::component::StorageType, bevy_ptr::OwningPtr<'_>),
368
) {
369
let target = <R::RelationshipTarget as RelationshipTarget>::with_capacity(1);
370
move_as_ptr!(target);
371
// SAFETY:
372
// - The caller must ensure that this is called exactly once before `apply_effect`.
373
// - Assuming `DynamicBundle` is implemented correctly for `R::Relationship` target, `func` should be
374
// called exactly once for each component being fetched with the correct `StorageType`
375
// - `Effect: !NoBundleEffect`, which means the caller is responsible for calling this type's `apply_effect`
376
// at least once before returning to safe code.
377
<R::RelationshipTarget as DynamicBundle>::get_components(target, func);
378
// Forget the pointer so that the value is available in `apply_effect`.
379
mem::forget(ptr);
380
}
381
382
unsafe fn apply_effect(ptr: MovingPtr<'_, MaybeUninit<Self>>, entity: &mut EntityWorldMut) {
383
// SAFETY: The value was not moved out in `get_components`, only borrowed, and thus should still
384
// be valid and initialized.
385
let effect = unsafe { ptr.assume_init() };
386
let effect = effect.read();
387
entity.with_related::<R>(effect.bundle);
388
}
389
}
390
391
// SAFETY: This internally relies on the RelationshipTarget's Bundle implementation, which is sound.
392
unsafe impl<R: Relationship, B: Bundle> Bundle for SpawnOneRelated<R, B> {
393
fn component_ids(
394
components: &mut crate::component::ComponentsRegistrator,
395
ids: &mut impl FnMut(crate::component::ComponentId),
396
) {
397
<R::RelationshipTarget as Bundle>::component_ids(components, ids);
398
}
399
400
fn get_component_ids(
401
components: &crate::component::Components,
402
ids: &mut impl FnMut(Option<crate::component::ComponentId>),
403
) {
404
<R::RelationshipTarget as Bundle>::get_component_ids(components, ids);
405
}
406
}
407
408
/// [`RelationshipTarget`] methods that create a [`Bundle`] with a [`DynamicBundle::Effect`] that:
409
///
410
/// 1. Contains the [`RelationshipTarget`] component, pre-allocated with the necessary space for spawned entities.
411
/// 2. Spawns an entity (or a list of entities) that relate to the entity the [`Bundle`] is added to via the [`RelationshipTarget::Relationship`].
412
pub trait SpawnRelated: RelationshipTarget {
413
/// Returns a [`Bundle`] containing this [`RelationshipTarget`] component. It also spawns a [`SpawnableList`] of entities, each related to the bundle's entity
414
/// via [`RelationshipTarget::Relationship`]. The [`RelationshipTarget`] (when possible) will pre-allocate space for the related entities.
415
///
416
/// See [`Spawn`], [`SpawnIter`], [`SpawnWith`], [`WithRelated`] and [`WithOneRelated`] for usage examples.
417
fn spawn<L: SpawnableList<Self::Relationship>>(
418
list: L,
419
) -> SpawnRelatedBundle<Self::Relationship, L>;
420
421
/// Returns a [`Bundle`] containing this [`RelationshipTarget`] component. It also spawns a single entity containing [`Bundle`] that is related to the bundle's entity
422
/// via [`RelationshipTarget::Relationship`].
423
///
424
/// ```
425
/// # use bevy_ecs::hierarchy::Children;
426
/// # use bevy_ecs::spawn::SpawnRelated;
427
/// # use bevy_ecs::name::Name;
428
/// # use bevy_ecs::world::World;
429
/// let mut world = World::new();
430
/// world.spawn((
431
/// Name::new("Root"),
432
/// Children::spawn_one(Name::new("Child")),
433
/// ));
434
/// ```
435
fn spawn_one<B: Bundle>(bundle: B) -> SpawnOneRelated<Self::Relationship, B>;
436
}
437
438
impl<T: RelationshipTarget> SpawnRelated for T {
439
fn spawn<L: SpawnableList<Self::Relationship>>(
440
list: L,
441
) -> SpawnRelatedBundle<Self::Relationship, L> {
442
SpawnRelatedBundle {
443
list,
444
marker: PhantomData,
445
}
446
}
447
448
fn spawn_one<B: Bundle>(bundle: B) -> SpawnOneRelated<Self::Relationship, B> {
449
SpawnOneRelated {
450
bundle,
451
marker: PhantomData,
452
}
453
}
454
}
455
456
/// Returns a [`SpawnRelatedBundle`] that will insert the given [`RelationshipTarget`], spawn a [`SpawnableList`] of entities with given bundles that
457
/// relate to the [`RelationshipTarget`] entity via the [`RelationshipTarget::Relationship`] component, and reserve space in the [`RelationshipTarget`] for each spawned entity.
458
///
459
/// The first argument is the [`RelationshipTarget`] type. Any additional arguments will be interpreted as bundles to be spawned.
460
///
461
/// Also see [`children`](crate::children) for a [`Children`](crate::hierarchy::Children)-specific equivalent.
462
///
463
/// ```
464
/// # use bevy_ecs::hierarchy::Children;
465
/// # use bevy_ecs::name::Name;
466
/// # use bevy_ecs::world::World;
467
/// # use bevy_ecs::related;
468
/// # use bevy_ecs::spawn::{Spawn, SpawnRelated};
469
/// let mut world = World::new();
470
/// world.spawn((
471
/// Name::new("Root"),
472
/// related!(Children[
473
/// Name::new("Child1"),
474
/// (
475
/// Name::new("Child2"),
476
/// related!(Children[
477
/// Name::new("Grandchild"),
478
/// ])
479
/// )
480
/// ])
481
/// ));
482
/// ```
483
#[macro_export]
484
macro_rules! related {
485
($relationship_target:ty [$($child:expr),*$(,)?]) => {
486
<$relationship_target>::spawn($crate::recursive_spawn!($($child),*))
487
};
488
}
489
490
// A tail-recursive spawn utility.
491
//
492
// Since `SpawnableList` is only implemented for tuples
493
// up to twelve elements long, this macro will nest
494
// longer sequences recursively. By default, this recursion
495
// will top out at around 1400 elements, but it would be
496
// ill-advised to spawn that many entities with this method.
497
//
498
// For spawning large batches of entities at a time,
499
// consider `SpawnIter` or eagerly spawning with `Commands`.
500
#[macro_export]
501
#[doc(hidden)]
502
macro_rules! recursive_spawn {
503
// direct expansion
504
() => { () };
505
($a:expr) => {
506
$crate::spawn::Spawn($a)
507
};
508
($a:expr, $b:expr) => {
509
(
510
$crate::spawn::Spawn($a),
511
$crate::spawn::Spawn($b),
512
)
513
};
514
($a:expr, $b:expr, $c:expr) => {
515
(
516
$crate::spawn::Spawn($a),
517
$crate::spawn::Spawn($b),
518
$crate::spawn::Spawn($c),
519
)
520
};
521
($a:expr, $b:expr, $c:expr, $d:expr) => {
522
(
523
$crate::spawn::Spawn($a),
524
$crate::spawn::Spawn($b),
525
$crate::spawn::Spawn($c),
526
$crate::spawn::Spawn($d),
527
)
528
};
529
($a:expr, $b:expr, $c:expr, $d:expr, $e:expr) => {
530
(
531
$crate::spawn::Spawn($a),
532
$crate::spawn::Spawn($b),
533
$crate::spawn::Spawn($c),
534
$crate::spawn::Spawn($d),
535
$crate::spawn::Spawn($e),
536
)
537
};
538
($a:expr, $b:expr, $c:expr, $d:expr, $e:expr, $f:expr) => {
539
(
540
$crate::spawn::Spawn($a),
541
$crate::spawn::Spawn($b),
542
$crate::spawn::Spawn($c),
543
$crate::spawn::Spawn($d),
544
$crate::spawn::Spawn($e),
545
$crate::spawn::Spawn($f),
546
)
547
};
548
($a:expr, $b:expr, $c:expr, $d:expr, $e:expr, $f:expr, $g:expr) => {
549
(
550
$crate::spawn::Spawn($a),
551
$crate::spawn::Spawn($b),
552
$crate::spawn::Spawn($c),
553
$crate::spawn::Spawn($d),
554
$crate::spawn::Spawn($e),
555
$crate::spawn::Spawn($f),
556
$crate::spawn::Spawn($g),
557
)
558
};
559
($a:expr, $b:expr, $c:expr, $d:expr, $e:expr, $f:expr, $g:expr, $h:expr) => {
560
(
561
$crate::spawn::Spawn($a),
562
$crate::spawn::Spawn($b),
563
$crate::spawn::Spawn($c),
564
$crate::spawn::Spawn($d),
565
$crate::spawn::Spawn($e),
566
$crate::spawn::Spawn($f),
567
$crate::spawn::Spawn($g),
568
$crate::spawn::Spawn($h),
569
)
570
};
571
($a:expr, $b:expr, $c:expr, $d:expr, $e:expr, $f:expr, $g:expr, $h:expr, $i:expr) => {
572
(
573
$crate::spawn::Spawn($a),
574
$crate::spawn::Spawn($b),
575
$crate::spawn::Spawn($c),
576
$crate::spawn::Spawn($d),
577
$crate::spawn::Spawn($e),
578
$crate::spawn::Spawn($f),
579
$crate::spawn::Spawn($g),
580
$crate::spawn::Spawn($h),
581
$crate::spawn::Spawn($i),
582
)
583
};
584
($a:expr, $b:expr, $c:expr, $d:expr, $e:expr, $f:expr, $g:expr, $h:expr, $i:expr, $j:expr) => {
585
(
586
$crate::spawn::Spawn($a),
587
$crate::spawn::Spawn($b),
588
$crate::spawn::Spawn($c),
589
$crate::spawn::Spawn($d),
590
$crate::spawn::Spawn($e),
591
$crate::spawn::Spawn($f),
592
$crate::spawn::Spawn($g),
593
$crate::spawn::Spawn($h),
594
$crate::spawn::Spawn($i),
595
$crate::spawn::Spawn($j),
596
)
597
};
598
($a:expr, $b:expr, $c:expr, $d:expr, $e:expr, $f:expr, $g:expr, $h:expr, $i:expr, $j:expr, $k:expr) => {
599
(
600
$crate::spawn::Spawn($a),
601
$crate::spawn::Spawn($b),
602
$crate::spawn::Spawn($c),
603
$crate::spawn::Spawn($d),
604
$crate::spawn::Spawn($e),
605
$crate::spawn::Spawn($f),
606
$crate::spawn::Spawn($g),
607
$crate::spawn::Spawn($h),
608
$crate::spawn::Spawn($i),
609
$crate::spawn::Spawn($j),
610
$crate::spawn::Spawn($k),
611
)
612
};
613
614
// recursive expansion
615
(
616
$a:expr, $b:expr, $c:expr, $d:expr, $e:expr, $f:expr,
617
$g:expr, $h:expr, $i:expr, $j:expr, $k:expr, $($rest:expr),*
618
) => {
619
(
620
$crate::spawn::Spawn($a),
621
$crate::spawn::Spawn($b),
622
$crate::spawn::Spawn($c),
623
$crate::spawn::Spawn($d),
624
$crate::spawn::Spawn($e),
625
$crate::spawn::Spawn($f),
626
$crate::spawn::Spawn($g),
627
$crate::spawn::Spawn($h),
628
$crate::spawn::Spawn($i),
629
$crate::spawn::Spawn($j),
630
$crate::spawn::Spawn($k),
631
$crate::recursive_spawn!($($rest),*)
632
)
633
};
634
}
635
636
#[cfg(test)]
637
mod tests {
638
639
use crate::{
640
name::Name,
641
prelude::{ChildOf, Children, RelationshipTarget},
642
relationship::RelatedSpawner,
643
world::World,
644
};
645
646
use super::{Spawn, SpawnIter, SpawnRelated, SpawnWith, WithOneRelated, WithRelated};
647
648
#[test]
649
fn spawn() {
650
let mut world = World::new();
651
652
let parent = world
653
.spawn((
654
Name::new("Parent"),
655
Children::spawn(Spawn(Name::new("Child1"))),
656
))
657
.id();
658
659
let children = world
660
.query::<&Children>()
661
.get(&world, parent)
662
.expect("An entity with Children should exist");
663
664
assert_eq!(children.iter().count(), 1);
665
666
for ChildOf(child) in world.query::<&ChildOf>().iter(&world) {
667
assert_eq!(child, &parent);
668
}
669
}
670
671
#[test]
672
fn spawn_iter() {
673
let mut world = World::new();
674
675
let parent = world
676
.spawn((
677
Name::new("Parent"),
678
Children::spawn(SpawnIter(["Child1", "Child2"].into_iter().map(Name::new))),
679
))
680
.id();
681
682
let children = world
683
.query::<&Children>()
684
.get(&world, parent)
685
.expect("An entity with Children should exist");
686
687
assert_eq!(children.iter().count(), 2);
688
689
for ChildOf(child) in world.query::<&ChildOf>().iter(&world) {
690
assert_eq!(child, &parent);
691
}
692
}
693
694
#[test]
695
fn spawn_with() {
696
let mut world = World::new();
697
698
let parent = world
699
.spawn((
700
Name::new("Parent"),
701
Children::spawn(SpawnWith(|parent: &mut RelatedSpawner<ChildOf>| {
702
parent.spawn(Name::new("Child1"));
703
})),
704
))
705
.id();
706
707
let children = world
708
.query::<&Children>()
709
.get(&world, parent)
710
.expect("An entity with Children should exist");
711
712
assert_eq!(children.iter().count(), 1);
713
714
for ChildOf(child) in world.query::<&ChildOf>().iter(&world) {
715
assert_eq!(child, &parent);
716
}
717
}
718
719
#[test]
720
fn with_related() {
721
let mut world = World::new();
722
723
let child1 = world.spawn(Name::new("Child1")).id();
724
let child2 = world.spawn(Name::new("Child2")).id();
725
726
let parent = world
727
.spawn((
728
Name::new("Parent"),
729
Children::spawn(WithRelated::new([child1, child2])),
730
))
731
.id();
732
733
let children = world
734
.query::<&Children>()
735
.get(&world, parent)
736
.expect("An entity with Children should exist");
737
738
assert_eq!(children.iter().count(), 2);
739
740
assert_eq!(
741
world.entity(child1).get::<ChildOf>(),
742
Some(&ChildOf(parent))
743
);
744
assert_eq!(
745
world.entity(child2).get::<ChildOf>(),
746
Some(&ChildOf(parent))
747
);
748
}
749
750
#[test]
751
fn with_one_related() {
752
let mut world = World::new();
753
754
let child1 = world.spawn(Name::new("Child1")).id();
755
756
let parent = world
757
.spawn((Name::new("Parent"), Children::spawn(WithOneRelated(child1))))
758
.id();
759
760
let children = world
761
.query::<&Children>()
762
.get(&world, parent)
763
.expect("An entity with Children should exist");
764
765
assert_eq!(children.iter().count(), 1);
766
767
assert_eq!(
768
world.entity(child1).get::<ChildOf>(),
769
Some(&ChildOf(parent))
770
);
771
}
772
}
773
774