Path: blob/main/crates/bevy_ecs/src/world/spawn_batch.rs
9354 views
use bevy_ptr::move_as_ptr;12use crate::{3bundle::{Bundle, BundleSpawner, NoBundleEffect},4change_detection::MaybeLocation,5entity::{AllocEntitiesIterator, Entity, EntitySetIterator},6world::World,7};8use core::iter::FusedIterator;910/// An iterator that spawns a series of entities and returns the [ID](Entity) of11/// each spawned entity.12///13/// If this iterator is not fully exhausted, any remaining entities will be spawned when this type is dropped.14pub struct SpawnBatchIter<'w, I>15where16I: Iterator,17I::Item: Bundle<Effect: NoBundleEffect>,18{19inner: I,20spawner: BundleSpawner<'w>,21allocator: AllocEntitiesIterator<'w>,22caller: MaybeLocation,23}2425impl<'w, I> SpawnBatchIter<'w, I>26where27I: Iterator,28I::Item: Bundle<Effect: NoBundleEffect>,29{30#[inline]31#[track_caller]32pub(crate) fn new(world: &'w mut World, iter: I, caller: MaybeLocation) -> Self {33let change_tick = world.change_tick();3435let (lower, upper) = iter.size_hint();36let length = upper.unwrap_or(lower);3738let mut spawner = BundleSpawner::new::<I::Item>(world, change_tick);39spawner.reserve_storage(length);40let allocator = spawner.allocator().alloc_many(length as u32);4142Self {43inner: iter,44allocator,45spawner,46caller,47}48}49}5051impl<I> Drop for SpawnBatchIter<'_, I>52where53I: Iterator,54I::Item: Bundle<Effect: NoBundleEffect>,55{56fn drop(&mut self) {57// Iterate through self in order to spawn remaining bundles.58for _ in &mut *self {}59// Apply any commands from those operations.60// SAFETY: `self.spawner` will be dropped immediately after this call.61unsafe { self.spawner.flush_commands() };62}63}6465impl<I> Iterator for SpawnBatchIter<'_, I>66where67I: Iterator,68I::Item: Bundle<Effect: NoBundleEffect>,69{70type Item = Entity;7172fn next(&mut self) -> Option<Entity> {73let bundle = self.inner.next()?;74move_as_ptr!(bundle);75Some(if let Some(bulk) = self.allocator.next() {76// SAFETY: bundle matches spawner type and we just allocated it77unsafe {78self.spawner.spawn_at(bulk, bundle, self.caller);79}80bulk81} else {82// SAFETY: bundle matches spawner type83unsafe { self.spawner.spawn(bundle, self.caller) }84})85}8687fn size_hint(&self) -> (usize, Option<usize>) {88self.inner.size_hint()89}90}9192impl<I, T> ExactSizeIterator for SpawnBatchIter<'_, I>93where94I: ExactSizeIterator<Item = T>,95T: Bundle<Effect: NoBundleEffect>,96{97fn len(&self) -> usize {98self.inner.len()99}100}101102impl<I, T> FusedIterator for SpawnBatchIter<'_, I>103where104I: FusedIterator<Item = T>,105T: Bundle<Effect: NoBundleEffect>,106{107}108109// SAFETY: Newly spawned entities are unique.110unsafe impl<I: Iterator, T> EntitySetIterator for SpawnBatchIter<'_, I>111where112I: FusedIterator<Item = T>,113T: Bundle<Effect: NoBundleEffect>,114{115}116117118