1use 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
19pub struct Spawn<B: Bundle>(pub B);
42
43pub trait SpawnableList<R>: Sized {
46 fn spawn(this: MovingPtr<'_, Self>, world: &mut World, entity: Entity);
52
53 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
103pub 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
135pub 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
171pub struct WithRelated<I>(pub I);
196
197impl<I> WithRelated<I> {
198 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
215pub 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
287pub struct SpawnRelatedBundle<R: Relationship, L: SpawnableList<R>> {
293 list: L,
294 marker: PhantomData<R>,
295}
296
297unsafe 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 unsafe { <R::RelationshipTarget as DynamicBundle>::get_components(target, func) };
331 mem::forget(ptr);
333 }
334
335 unsafe fn apply_effect(ptr: MovingPtr<'_, MaybeUninit<Self>>, entity: &mut EntityWorldMut) {
336 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
350pub 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 unsafe { <R::RelationshipTarget as DynamicBundle>::get_components(target, func) };
376 mem::forget(ptr);
378 }
379
380 unsafe fn apply_effect(ptr: MovingPtr<'_, MaybeUninit<Self>>, entity: &mut EntityWorldMut) {
381 let effect = unsafe { ptr.assume_init() };
384 let effect = effect.read();
385 entity.with_related::<R>(effect.bundle);
386 }
387}
388
389unsafe 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
404pub trait SpawnRelated: RelationshipTarget {
409 fn spawn<L: SpawnableList<Self::Relationship>>(
414 list: L,
415 ) -> SpawnRelatedBundle<Self::Relationship, L>;
416
417 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#[macro_export]
479macro_rules! related {
480 ($relationship_target:ty [$($child:expr),*$(,)?]) => {
481 <$relationship_target as $crate::spawn::SpawnRelated>::spawn($crate::recursive_spawn!($($child),*))
482 };
483}
484
485#[macro_export]
496#[doc(hidden)]
497macro_rules! recursive_spawn {
498 () => { () };
500 ($a:expr) => {
501 $crate::spawn::Spawn($a)
502 };
503 ($a:expr, $b:expr) => {
504 (
505 $crate::spawn::Spawn($a),
506 $crate::spawn::Spawn($b),
507 )
508 };
509 ($a:expr, $b:expr, $c:expr) => {
510 (
511 $crate::spawn::Spawn($a),
512 $crate::spawn::Spawn($b),
513 $crate::spawn::Spawn($c),
514 )
515 };
516 ($a:expr, $b:expr, $c:expr, $d:expr) => {
517 (
518 $crate::spawn::Spawn($a),
519 $crate::spawn::Spawn($b),
520 $crate::spawn::Spawn($c),
521 $crate::spawn::Spawn($d),
522 )
523 };
524 ($a:expr, $b:expr, $c:expr, $d:expr, $e:expr) => {
525 (
526 $crate::spawn::Spawn($a),
527 $crate::spawn::Spawn($b),
528 $crate::spawn::Spawn($c),
529 $crate::spawn::Spawn($d),
530 $crate::spawn::Spawn($e),
531 )
532 };
533 ($a:expr, $b:expr, $c:expr, $d:expr, $e:expr, $f:expr) => {
534 (
535 $crate::spawn::Spawn($a),
536 $crate::spawn::Spawn($b),
537 $crate::spawn::Spawn($c),
538 $crate::spawn::Spawn($d),
539 $crate::spawn::Spawn($e),
540 $crate::spawn::Spawn($f),
541 )
542 };
543 ($a:expr, $b:expr, $c:expr, $d:expr, $e:expr, $f:expr, $g:expr) => {
544 (
545 $crate::spawn::Spawn($a),
546 $crate::spawn::Spawn($b),
547 $crate::spawn::Spawn($c),
548 $crate::spawn::Spawn($d),
549 $crate::spawn::Spawn($e),
550 $crate::spawn::Spawn($f),
551 $crate::spawn::Spawn($g),
552 )
553 };
554 ($a:expr, $b:expr, $c:expr, $d:expr, $e:expr, $f:expr, $g:expr, $h:expr) => {
555 (
556 $crate::spawn::Spawn($a),
557 $crate::spawn::Spawn($b),
558 $crate::spawn::Spawn($c),
559 $crate::spawn::Spawn($d),
560 $crate::spawn::Spawn($e),
561 $crate::spawn::Spawn($f),
562 $crate::spawn::Spawn($g),
563 $crate::spawn::Spawn($h),
564 )
565 };
566 ($a:expr, $b:expr, $c:expr, $d:expr, $e:expr, $f:expr, $g:expr, $h:expr, $i:expr) => {
567 (
568 $crate::spawn::Spawn($a),
569 $crate::spawn::Spawn($b),
570 $crate::spawn::Spawn($c),
571 $crate::spawn::Spawn($d),
572 $crate::spawn::Spawn($e),
573 $crate::spawn::Spawn($f),
574 $crate::spawn::Spawn($g),
575 $crate::spawn::Spawn($h),
576 $crate::spawn::Spawn($i),
577 )
578 };
579 ($a:expr, $b:expr, $c:expr, $d:expr, $e:expr, $f:expr, $g:expr, $h:expr, $i:expr, $j:expr) => {
580 (
581 $crate::spawn::Spawn($a),
582 $crate::spawn::Spawn($b),
583 $crate::spawn::Spawn($c),
584 $crate::spawn::Spawn($d),
585 $crate::spawn::Spawn($e),
586 $crate::spawn::Spawn($f),
587 $crate::spawn::Spawn($g),
588 $crate::spawn::Spawn($h),
589 $crate::spawn::Spawn($i),
590 $crate::spawn::Spawn($j),
591 )
592 };
593 ($a:expr, $b:expr, $c:expr, $d:expr, $e:expr, $f:expr, $g:expr, $h:expr, $i:expr, $j:expr, $k:expr) => {
594 (
595 $crate::spawn::Spawn($a),
596 $crate::spawn::Spawn($b),
597 $crate::spawn::Spawn($c),
598 $crate::spawn::Spawn($d),
599 $crate::spawn::Spawn($e),
600 $crate::spawn::Spawn($f),
601 $crate::spawn::Spawn($g),
602 $crate::spawn::Spawn($h),
603 $crate::spawn::Spawn($i),
604 $crate::spawn::Spawn($j),
605 $crate::spawn::Spawn($k),
606 )
607 };
608
609 (
611 $a:expr, $b:expr, $c:expr, $d:expr, $e:expr, $f:expr,
612 $g:expr, $h:expr, $i:expr, $j:expr, $k:expr, $($rest:expr),*
613 ) => {
614 (
615 $crate::spawn::Spawn($a),
616 $crate::spawn::Spawn($b),
617 $crate::spawn::Spawn($c),
618 $crate::spawn::Spawn($d),
619 $crate::spawn::Spawn($e),
620 $crate::spawn::Spawn($f),
621 $crate::spawn::Spawn($g),
622 $crate::spawn::Spawn($h),
623 $crate::spawn::Spawn($i),
624 $crate::spawn::Spawn($j),
625 $crate::spawn::Spawn($k),
626 $crate::recursive_spawn!($($rest),*)
627 )
628 };
629}
630
631#[cfg(test)]
632mod tests {
633
634 use crate::{
635 name::Name,
636 prelude::{ChildOf, Children, RelationshipTarget},
637 relationship::RelatedSpawner,
638 world::World,
639 };
640
641 use super::{Spawn, SpawnIter, SpawnRelated, SpawnWith, WithOneRelated, WithRelated};
642
643 #[test]
644 fn spawn() {
645 let mut world = World::new();
646
647 let parent = world
648 .spawn((
649 Name::new("Parent"),
650 Children::spawn(Spawn(Name::new("Child1"))),
651 ))
652 .id();
653
654 let children = world
655 .query::<&Children>()
656 .get(&world, parent)
657 .expect("An entity with Children should exist");
658
659 assert_eq!(children.iter().count(), 1);
660
661 for ChildOf(child) in world.query::<&ChildOf>().iter(&world) {
662 assert_eq!(child, &parent);
663 }
664 }
665
666 #[test]
667 fn spawn_iter() {
668 let mut world = World::new();
669
670 let parent = world
671 .spawn((
672 Name::new("Parent"),
673 Children::spawn(SpawnIter(["Child1", "Child2"].into_iter().map(Name::new))),
674 ))
675 .id();
676
677 let children = world
678 .query::<&Children>()
679 .get(&world, parent)
680 .expect("An entity with Children should exist");
681
682 assert_eq!(children.iter().count(), 2);
683
684 for ChildOf(child) in world.query::<&ChildOf>().iter(&world) {
685 assert_eq!(child, &parent);
686 }
687 }
688
689 #[test]
690 fn spawn_with() {
691 let mut world = World::new();
692
693 let parent = world
694 .spawn((
695 Name::new("Parent"),
696 Children::spawn(SpawnWith(|parent: &mut RelatedSpawner<ChildOf>| {
697 parent.spawn(Name::new("Child1"));
698 })),
699 ))
700 .id();
701
702 let children = world
703 .query::<&Children>()
704 .get(&world, parent)
705 .expect("An entity with Children should exist");
706
707 assert_eq!(children.iter().count(), 1);
708
709 for ChildOf(child) in world.query::<&ChildOf>().iter(&world) {
710 assert_eq!(child, &parent);
711 }
712 }
713
714 #[test]
715 fn with_related() {
716 let mut world = World::new();
717
718 let child1 = world.spawn(Name::new("Child1")).id();
719 let child2 = world.spawn(Name::new("Child2")).id();
720
721 let parent = world
722 .spawn((
723 Name::new("Parent"),
724 Children::spawn(WithRelated::new([child1, child2])),
725 ))
726 .id();
727
728 let children = world
729 .query::<&Children>()
730 .get(&world, parent)
731 .expect("An entity with Children should exist");
732
733 assert_eq!(children.iter().count(), 2);
734
735 assert_eq!(
736 world.entity(child1).get::<ChildOf>(),
737 Some(&ChildOf(parent))
738 );
739 assert_eq!(
740 world.entity(child2).get::<ChildOf>(),
741 Some(&ChildOf(parent))
742 );
743 }
744
745 #[test]
746 fn with_one_related() {
747 let mut world = World::new();
748
749 let child1 = world.spawn(Name::new("Child1")).id();
750
751 let parent = world
752 .spawn((Name::new("Parent"), Children::spawn(WithOneRelated(child1))))
753 .id();
754
755 let children = world
756 .query::<&Children>()
757 .get(&world, parent)
758 .expect("An entity with Children should exist");
759
760 assert_eq!(children.iter().count(), 1);
761
762 assert_eq!(
763 world.entity(child1).get::<ChildOf>(),
764 Some(&ChildOf(parent))
765 );
766 }
767}