Path: blob/main/crates/bevy_ecs/src/world/spawn_batch.rs
6849 views
use bevy_ptr::move_as_ptr;12use crate::{3bundle::{Bundle, BundleSpawner, NoBundleEffect},4change_detection::MaybeLocation,5entity::{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>,21caller: MaybeLocation,22}2324impl<'w, I> SpawnBatchIter<'w, I>25where26I: Iterator,27I::Item: Bundle<Effect: NoBundleEffect>,28{29#[inline]30#[track_caller]31pub(crate) fn new(world: &'w mut World, iter: I, caller: MaybeLocation) -> Self {32// Ensure all entity allocations are accounted for so `self.entities` can realloc if33// necessary34world.flush();3536let change_tick = world.change_tick();3738let (lower, upper) = iter.size_hint();39let length = upper.unwrap_or(lower);40world.entities.reserve(length as u32);4142let mut spawner = BundleSpawner::new::<I::Item>(world, change_tick);43spawner.reserve_storage(length);4445Self {46inner: iter,47spawner,48caller,49}50}51}5253impl<I> Drop for SpawnBatchIter<'_, I>54where55I: Iterator,56I::Item: Bundle<Effect: NoBundleEffect>,57{58fn drop(&mut self) {59// Iterate through self in order to spawn remaining bundles.60for _ in &mut *self {}61// Apply any commands from those operations.62// SAFETY: `self.spawner` will be dropped immediately after this call.63unsafe { self.spawner.flush_commands() };64}65}6667impl<I> Iterator for SpawnBatchIter<'_, I>68where69I: Iterator,70I::Item: Bundle<Effect: NoBundleEffect>,71{72type Item = Entity;7374fn next(&mut self) -> Option<Entity> {75let bundle = self.inner.next()?;76move_as_ptr!(bundle);77// SAFETY:78// - The spawner matches `I::Item`'s type.79// - `I::Item::Effect: NoBundleEffect`, thus [`apply_effect`] does not need to be called.80// - `bundle` is not accessed or dropped after this function call.81unsafe { Some(self.spawner.spawn::<I::Item>(bundle, self.caller)) }82}8384fn size_hint(&self) -> (usize, Option<usize>) {85self.inner.size_hint()86}87}8889impl<I, T> ExactSizeIterator for SpawnBatchIter<'_, I>90where91I: ExactSizeIterator<Item = T>,92T: Bundle<Effect: NoBundleEffect>,93{94fn len(&self) -> usize {95self.inner.len()96}97}9899impl<I, T> FusedIterator for SpawnBatchIter<'_, I>100where101I: FusedIterator<Item = T>,102T: Bundle<Effect: NoBundleEffect>,103{104}105106// SAFETY: Newly spawned entities are unique.107unsafe impl<I: Iterator, T> EntitySetIterator for SpawnBatchIter<'_, I>108where109I: FusedIterator<Item = T>,110T: Bundle<Effect: NoBundleEffect>,111{112}113114115