bevy_ecs/
spawn.rs

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