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        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
316impl<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`].
357pub struct SpawnOneRelated<R: Relationship, B: Bundle> {
358    bundle: B,
359    marker: PhantomData<R>,
360}
361
362impl<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.
392unsafe 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`].
412pub 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
438impl<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]
484macro_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)]
502macro_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)]
637mod 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}