beet_core 0.0.8

Core utilities and types for other beet crates
use crate::prelude::OnSpawn;
use beet_core_macros::BundleEffect;
use bevy::ecs::relationship::Relationship;
use std::marker::PhantomData;

/// Add to a temporary entity spawned as a child of another entity.
/// When spawned, each item in the iterator will be added as a child
/// of the parent entity, and this entity will be removed.
///
/// ## Panics
///
/// If the entity has no parent of this relationship type
///
/// This method will remove this entity, any other bundles attempting
/// to access it after will panic.
pub fn spawn_siblings<R, B>(
	iter: impl 'static + Send + Sync + IntoIterator<Item = B>,
) -> impl Bundle
where
	R: RelationshipTarget,
	B: Bundle,
{
	OnSpawn::new(move |entity| {
		let parent = entity
			.get::<R::Relationship>()
			.expect("Spawn Siblings: This entity has no parent, this can happen due to
bundle effect race conditions, try reordering the effects")
			.get();
		let id = entity.id();
		entity.world_scope(|world| {
			for bundle in iter {
				world.spawn((
					bundle,
					<R::Relationship as Relationship>::from(parent),
				));
			}
			world.entity_mut(id).despawn();
			// defer removal to avoid panic?
			// world.commands().entity(id).despawn();
		});
	})
}

/// Like [`SpawnIter`] but for bundles, calling [`EntityWorldMut::insert`].
#[derive(BundleEffect)]
pub struct BundleIter<T, B>
where
	T: 'static + Send + Sync + Iterator<Item = B>,
	B: Bundle,
{
	pub value: T,
	_phantom: PhantomData<B>,
}

impl<T, B> BundleIter<T, B>
where
	T: 'static + Send + Sync + Iterator<Item = B>,
	B: Bundle,
{
	/// Create a new [`BundleIter`] effect.
	pub fn new(iter: T) -> Self {
		Self {
			value: iter,
			_phantom: PhantomData,
		}
	}
	fn effect(self, entity: &mut EntityWorldMut) {
		for bundle in self.value {
			entity.insert(bundle);
		}
	}
}


#[cfg(test)]
mod test {
	use crate::prelude::*;

	#[test]
	fn works() {
		let mut world = World::new();
		let entity = world
			.spawn(children![spawn_siblings::<Children, Name>(vec![
				Name::new("Child1"),
				Name::new("Child2"),
			])])
			.id();
		// world.flush();

		let children = world.entity(entity).get::<Children>().unwrap();
		children.len().xpect_eq(2);
	}
}