Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
bevyengine
GitHub Repository: bevyengine/bevy
Path: blob/main/crates/bevy_ecs/src/spawn.rs
9349 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
) -> impl Iterator<Item = crate::component::ComponentId> + use<R, L> {
304
<R::RelationshipTarget as Bundle>::component_ids(components)
305
}
306
307
fn get_component_ids(
308
components: &crate::component::Components,
309
) -> impl Iterator<Item = Option<crate::component::ComponentId>> {
310
<R::RelationshipTarget as Bundle>::get_component_ids(components)
311
}
312
}
313
314
impl<R: Relationship, L: SpawnableList<R>> DynamicBundle for SpawnRelatedBundle<R, L> {
315
type Effect = Self;
316
317
unsafe fn get_components(
318
ptr: MovingPtr<'_, Self>,
319
func: &mut impl FnMut(crate::component::StorageType, bevy_ptr::OwningPtr<'_>),
320
) {
321
let target =
322
<R::RelationshipTarget as RelationshipTarget>::with_capacity(ptr.list.size_hint());
323
move_as_ptr!(target);
324
// SAFETY:
325
// - The caller must ensure that this is called exactly once before `apply_effect`.
326
// - Assuming `DynamicBundle` is implemented correctly for `R::Relationship` target, `func` should be
327
// called exactly once for each component being fetched with the correct `StorageType`
328
// - `Effect: !NoBundleEffect`, which means the caller is responsible for calling this type's `apply_effect`
329
// at least once before returning to safe code.
330
unsafe { <R::RelationshipTarget as DynamicBundle>::get_components(target, func) };
331
// Forget the pointer so that the value is available in `apply_effect`.
332
mem::forget(ptr);
333
}
334
335
unsafe fn apply_effect(ptr: MovingPtr<'_, MaybeUninit<Self>>, entity: &mut EntityWorldMut) {
336
// SAFETY: The value was not moved out in `get_components`, only borrowed, and thus should still
337
// be valid and initialized.
338
let effect = unsafe { ptr.assume_init() };
339
bevy_ptr::deconstruct_moving_ptr!({
340
let Self { list, marker: _ } = effect;
341
});
342
let id = entity.id();
343
344
if entity.is_despawned() {
345
return;
346
}
347
348
entity.world_scope(|world: &mut World| {
349
L::spawn(list, world, id);
350
});
351
}
352
}
353
354
/// A [`Bundle`] that:
355
/// 1. Contains a [`RelationshipTarget`] component (associated with the given [`Relationship`]). This reserves space for a single entity.
356
/// 2. Spawns a single related entity containing the given `B` [`Bundle`] and the given [`Relationship`].
357
///
358
/// This is intended to be created using [`SpawnRelated`].
359
pub struct SpawnOneRelated<R: Relationship, B: Bundle> {
360
bundle: B,
361
marker: PhantomData<R>,
362
}
363
364
impl<R: Relationship, B: Bundle> DynamicBundle for SpawnOneRelated<R, B> {
365
type Effect = Self;
366
367
unsafe fn get_components(
368
ptr: MovingPtr<'_, Self>,
369
func: &mut impl FnMut(crate::component::StorageType, bevy_ptr::OwningPtr<'_>),
370
) {
371
let target = <R::RelationshipTarget as RelationshipTarget>::with_capacity(1);
372
move_as_ptr!(target);
373
// SAFETY:
374
// - The caller must ensure that this is called exactly once before `apply_effect`.
375
// - Assuming `DynamicBundle` is implemented correctly for `R::Relationship` target, `func` should be
376
// called exactly once for each component being fetched with the correct `StorageType`
377
// - `Effect: !NoBundleEffect`, which means the caller is responsible for calling this type's `apply_effect`
378
// at least once before returning to safe code.
379
unsafe { <R::RelationshipTarget as DynamicBundle>::get_components(target, func) };
380
// Forget the pointer so that the value is available in `apply_effect`.
381
mem::forget(ptr);
382
}
383
384
unsafe fn apply_effect(ptr: MovingPtr<'_, MaybeUninit<Self>>, entity: &mut EntityWorldMut) {
385
// SAFETY: The value was not moved out in `get_components`, only borrowed, and thus should still
386
// be valid and initialized.
387
let effect = unsafe { ptr.assume_init() };
388
if entity.is_despawned() {
389
return;
390
}
391
392
let effect = effect.read();
393
entity.with_related::<R>(effect.bundle);
394
}
395
}
396
397
// SAFETY: This internally relies on the RelationshipTarget's Bundle implementation, which is sound.
398
unsafe impl<R: Relationship, B: Bundle> Bundle for SpawnOneRelated<R, B> {
399
fn component_ids(
400
components: &mut crate::component::ComponentsRegistrator,
401
) -> impl Iterator<Item = crate::component::ComponentId> + use<R, B> {
402
<R::RelationshipTarget as Bundle>::component_ids(components)
403
}
404
405
fn get_component_ids(
406
components: &crate::component::Components,
407
) -> impl Iterator<Item = Option<crate::component::ComponentId>> {
408
<R::RelationshipTarget as Bundle>::get_component_ids(components)
409
}
410
}
411
412
/// [`RelationshipTarget`] methods that create a [`Bundle`] with a [`DynamicBundle::Effect`] that:
413
///
414
/// 1. Contains the [`RelationshipTarget`] component, pre-allocated with the necessary space for spawned entities.
415
/// 2. Spawns an entity (or a list of entities) that relate to the entity the [`Bundle`] is added to via the [`RelationshipTarget::Relationship`].
416
pub trait SpawnRelated: RelationshipTarget {
417
/// Returns a [`Bundle`] containing this [`RelationshipTarget`] component. It also spawns a [`SpawnableList`] of entities, each related to the bundle's entity
418
/// via [`RelationshipTarget::Relationship`]. The [`RelationshipTarget`] (when possible) will pre-allocate space for the related entities.
419
///
420
/// See [`Spawn`], [`SpawnIter`], [`SpawnWith`], [`WithRelated`] and [`WithOneRelated`] for usage examples.
421
fn spawn<L: SpawnableList<Self::Relationship>>(
422
list: L,
423
) -> SpawnRelatedBundle<Self::Relationship, L>;
424
425
/// Returns a [`Bundle`] containing this [`RelationshipTarget`] component. It also spawns a single entity containing [`Bundle`] that is related to the bundle's entity
426
/// via [`RelationshipTarget::Relationship`].
427
///
428
/// ```
429
/// # use bevy_ecs::hierarchy::Children;
430
/// # use bevy_ecs::spawn::SpawnRelated;
431
/// # use bevy_ecs::name::Name;
432
/// # use bevy_ecs::world::World;
433
/// let mut world = World::new();
434
/// world.spawn((
435
/// Name::new("Root"),
436
/// Children::spawn_one(Name::new("Child")),
437
/// ));
438
/// ```
439
fn spawn_one<B: Bundle>(bundle: B) -> SpawnOneRelated<Self::Relationship, B>;
440
}
441
442
impl<T: RelationshipTarget> SpawnRelated for T {
443
fn spawn<L: SpawnableList<Self::Relationship>>(
444
list: L,
445
) -> SpawnRelatedBundle<Self::Relationship, L> {
446
SpawnRelatedBundle {
447
list,
448
marker: PhantomData,
449
}
450
}
451
452
fn spawn_one<B: Bundle>(bundle: B) -> SpawnOneRelated<Self::Relationship, B> {
453
SpawnOneRelated {
454
bundle,
455
marker: PhantomData,
456
}
457
}
458
}
459
460
/// Returns a [`SpawnRelatedBundle`] that will insert the given [`RelationshipTarget`], spawn a [`SpawnableList`] of entities with given bundles that
461
/// relate to the [`RelationshipTarget`] entity via the [`RelationshipTarget::Relationship`] component, and reserve space in the [`RelationshipTarget`] for each spawned entity.
462
///
463
/// The first argument is the [`RelationshipTarget`] type. Any additional arguments will be interpreted as bundles to be spawned.
464
///
465
/// Also see [`children`](crate::children) for a [`Children`](crate::hierarchy::Children)-specific equivalent.
466
///
467
/// ```
468
/// # use bevy_ecs::hierarchy::Children;
469
/// # use bevy_ecs::name::Name;
470
/// # use bevy_ecs::world::World;
471
/// # use bevy_ecs::related;
472
/// let mut world = World::new();
473
/// world.spawn((
474
/// Name::new("Root"),
475
/// related!(Children[
476
/// Name::new("Child1"),
477
/// (
478
/// Name::new("Child2"),
479
/// related!(Children[
480
/// Name::new("Grandchild"),
481
/// ])
482
/// )
483
/// ])
484
/// ));
485
/// ```
486
#[macro_export]
487
macro_rules! related {
488
($relationship_target:ty [$($child:expr),*$(,)?]) => {
489
<$relationship_target as $crate::spawn::SpawnRelated>::spawn($crate::recursive_spawn!($($child),*))
490
};
491
}
492
493
// A tail-recursive spawn utility.
494
//
495
// Since `SpawnableList` is only implemented for tuples
496
// up to twelve elements long, this macro will nest
497
// longer sequences recursively. By default, this recursion
498
// will top out at around 1400 elements, but it would be
499
// ill-advised to spawn that many entities with this method.
500
//
501
// For spawning large batches of entities at a time,
502
// consider `SpawnIter` or eagerly spawning with `Commands`.
503
#[macro_export]
504
#[doc(hidden)]
505
macro_rules! recursive_spawn {
506
// direct expansion
507
() => { () };
508
($a:expr) => {
509
$crate::spawn::Spawn($a)
510
};
511
($a:expr, $b:expr) => {
512
(
513
$crate::spawn::Spawn($a),
514
$crate::spawn::Spawn($b),
515
)
516
};
517
($a:expr, $b:expr, $c:expr) => {
518
(
519
$crate::spawn::Spawn($a),
520
$crate::spawn::Spawn($b),
521
$crate::spawn::Spawn($c),
522
)
523
};
524
($a:expr, $b:expr, $c:expr, $d:expr) => {
525
(
526
$crate::spawn::Spawn($a),
527
$crate::spawn::Spawn($b),
528
$crate::spawn::Spawn($c),
529
$crate::spawn::Spawn($d),
530
)
531
};
532
($a:expr, $b:expr, $c:expr, $d:expr, $e:expr) => {
533
(
534
$crate::spawn::Spawn($a),
535
$crate::spawn::Spawn($b),
536
$crate::spawn::Spawn($c),
537
$crate::spawn::Spawn($d),
538
$crate::spawn::Spawn($e),
539
)
540
};
541
($a:expr, $b:expr, $c:expr, $d:expr, $e:expr, $f:expr) => {
542
(
543
$crate::spawn::Spawn($a),
544
$crate::spawn::Spawn($b),
545
$crate::spawn::Spawn($c),
546
$crate::spawn::Spawn($d),
547
$crate::spawn::Spawn($e),
548
$crate::spawn::Spawn($f),
549
)
550
};
551
($a:expr, $b:expr, $c:expr, $d:expr, $e:expr, $f:expr, $g:expr) => {
552
(
553
$crate::spawn::Spawn($a),
554
$crate::spawn::Spawn($b),
555
$crate::spawn::Spawn($c),
556
$crate::spawn::Spawn($d),
557
$crate::spawn::Spawn($e),
558
$crate::spawn::Spawn($f),
559
$crate::spawn::Spawn($g),
560
)
561
};
562
($a:expr, $b:expr, $c:expr, $d:expr, $e:expr, $f:expr, $g:expr, $h:expr) => {
563
(
564
$crate::spawn::Spawn($a),
565
$crate::spawn::Spawn($b),
566
$crate::spawn::Spawn($c),
567
$crate::spawn::Spawn($d),
568
$crate::spawn::Spawn($e),
569
$crate::spawn::Spawn($f),
570
$crate::spawn::Spawn($g),
571
$crate::spawn::Spawn($h),
572
)
573
};
574
($a:expr, $b:expr, $c:expr, $d:expr, $e:expr, $f:expr, $g:expr, $h:expr, $i:expr) => {
575
(
576
$crate::spawn::Spawn($a),
577
$crate::spawn::Spawn($b),
578
$crate::spawn::Spawn($c),
579
$crate::spawn::Spawn($d),
580
$crate::spawn::Spawn($e),
581
$crate::spawn::Spawn($f),
582
$crate::spawn::Spawn($g),
583
$crate::spawn::Spawn($h),
584
$crate::spawn::Spawn($i),
585
)
586
};
587
($a:expr, $b:expr, $c:expr, $d:expr, $e:expr, $f:expr, $g:expr, $h:expr, $i:expr, $j:expr) => {
588
(
589
$crate::spawn::Spawn($a),
590
$crate::spawn::Spawn($b),
591
$crate::spawn::Spawn($c),
592
$crate::spawn::Spawn($d),
593
$crate::spawn::Spawn($e),
594
$crate::spawn::Spawn($f),
595
$crate::spawn::Spawn($g),
596
$crate::spawn::Spawn($h),
597
$crate::spawn::Spawn($i),
598
$crate::spawn::Spawn($j),
599
)
600
};
601
($a:expr, $b:expr, $c:expr, $d:expr, $e:expr, $f:expr, $g:expr, $h:expr, $i:expr, $j:expr, $k:expr) => {
602
(
603
$crate::spawn::Spawn($a),
604
$crate::spawn::Spawn($b),
605
$crate::spawn::Spawn($c),
606
$crate::spawn::Spawn($d),
607
$crate::spawn::Spawn($e),
608
$crate::spawn::Spawn($f),
609
$crate::spawn::Spawn($g),
610
$crate::spawn::Spawn($h),
611
$crate::spawn::Spawn($i),
612
$crate::spawn::Spawn($j),
613
$crate::spawn::Spawn($k),
614
)
615
};
616
617
// recursive expansion
618
(
619
$a:expr, $b:expr, $c:expr, $d:expr, $e:expr, $f:expr,
620
$g:expr, $h:expr, $i:expr, $j:expr, $k:expr, $($rest:expr),*
621
) => {
622
(
623
$crate::spawn::Spawn($a),
624
$crate::spawn::Spawn($b),
625
$crate::spawn::Spawn($c),
626
$crate::spawn::Spawn($d),
627
$crate::spawn::Spawn($e),
628
$crate::spawn::Spawn($f),
629
$crate::spawn::Spawn($g),
630
$crate::spawn::Spawn($h),
631
$crate::spawn::Spawn($i),
632
$crate::spawn::Spawn($j),
633
$crate::spawn::Spawn($k),
634
$crate::recursive_spawn!($($rest),*)
635
)
636
};
637
}
638
639
#[cfg(test)]
640
mod tests {
641
642
use crate::{
643
name::Name,
644
prelude::{ChildOf, Children, RelationshipTarget},
645
relationship::RelatedSpawner,
646
world::World,
647
};
648
649
use super::{Spawn, SpawnIter, SpawnRelated, SpawnWith, WithOneRelated, WithRelated};
650
651
#[test]
652
fn spawn() {
653
let mut world = World::new();
654
655
let parent = world
656
.spawn((
657
Name::new("Parent"),
658
Children::spawn(Spawn(Name::new("Child1"))),
659
))
660
.id();
661
662
let children = world
663
.query::<&Children>()
664
.get(&world, parent)
665
.expect("An entity with Children should exist");
666
667
assert_eq!(children.iter().count(), 1);
668
669
for ChildOf(child) in world.query::<&ChildOf>().iter(&world) {
670
assert_eq!(child, &parent);
671
}
672
}
673
674
#[test]
675
fn spawn_iter() {
676
let mut world = World::new();
677
678
let parent = world
679
.spawn((
680
Name::new("Parent"),
681
Children::spawn(SpawnIter(["Child1", "Child2"].into_iter().map(Name::new))),
682
))
683
.id();
684
685
let children = world
686
.query::<&Children>()
687
.get(&world, parent)
688
.expect("An entity with Children should exist");
689
690
assert_eq!(children.iter().count(), 2);
691
692
for ChildOf(child) in world.query::<&ChildOf>().iter(&world) {
693
assert_eq!(child, &parent);
694
}
695
}
696
697
#[test]
698
fn spawn_with() {
699
let mut world = World::new();
700
701
let parent = world
702
.spawn((
703
Name::new("Parent"),
704
Children::spawn(SpawnWith(|parent: &mut RelatedSpawner<ChildOf>| {
705
parent.spawn(Name::new("Child1"));
706
})),
707
))
708
.id();
709
710
let children = world
711
.query::<&Children>()
712
.get(&world, parent)
713
.expect("An entity with Children should exist");
714
715
assert_eq!(children.iter().count(), 1);
716
717
for ChildOf(child) in world.query::<&ChildOf>().iter(&world) {
718
assert_eq!(child, &parent);
719
}
720
}
721
722
#[test]
723
fn with_related() {
724
let mut world = World::new();
725
726
let child1 = world.spawn(Name::new("Child1")).id();
727
let child2 = world.spawn(Name::new("Child2")).id();
728
729
let parent = world
730
.spawn((
731
Name::new("Parent"),
732
Children::spawn(WithRelated::new([child1, child2])),
733
))
734
.id();
735
736
let children = world
737
.query::<&Children>()
738
.get(&world, parent)
739
.expect("An entity with Children should exist");
740
741
assert_eq!(children.iter().count(), 2);
742
743
assert_eq!(
744
world.entity(child1).get::<ChildOf>(),
745
Some(&ChildOf(parent))
746
);
747
assert_eq!(
748
world.entity(child2).get::<ChildOf>(),
749
Some(&ChildOf(parent))
750
);
751
}
752
753
#[test]
754
fn with_one_related() {
755
let mut world = World::new();
756
757
let child1 = world.spawn(Name::new("Child1")).id();
758
759
let parent = world
760
.spawn((Name::new("Parent"), Children::spawn(WithOneRelated(child1))))
761
.id();
762
763
let children = world
764
.query::<&Children>()
765
.get(&world, parent)
766
.expect("An entity with Children should exist");
767
768
assert_eq!(children.iter().count(), 1);
769
770
assert_eq!(
771
world.entity(child1).get::<ChildOf>(),
772
Some(&ChildOf(parent))
773
);
774
}
775
}
776
777