Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
bevyengine
GitHub Repository: bevyengine/bevy
Path: blob/main/crates/bevy_ecs/src/world/spawn_batch.rs
9354 views
1
use bevy_ptr::move_as_ptr;
2
3
use crate::{
4
bundle::{Bundle, BundleSpawner, NoBundleEffect},
5
change_detection::MaybeLocation,
6
entity::{AllocEntitiesIterator, Entity, EntitySetIterator},
7
world::World,
8
};
9
use core::iter::FusedIterator;
10
11
/// An iterator that spawns a series of entities and returns the [ID](Entity) of
12
/// each spawned entity.
13
///
14
/// If this iterator is not fully exhausted, any remaining entities will be spawned when this type is dropped.
15
pub struct SpawnBatchIter<'w, I>
16
where
17
I: Iterator,
18
I::Item: Bundle<Effect: NoBundleEffect>,
19
{
20
inner: I,
21
spawner: BundleSpawner<'w>,
22
allocator: AllocEntitiesIterator<'w>,
23
caller: MaybeLocation,
24
}
25
26
impl<'w, I> SpawnBatchIter<'w, I>
27
where
28
I: Iterator,
29
I::Item: Bundle<Effect: NoBundleEffect>,
30
{
31
#[inline]
32
#[track_caller]
33
pub(crate) fn new(world: &'w mut World, iter: I, caller: MaybeLocation) -> Self {
34
let change_tick = world.change_tick();
35
36
let (lower, upper) = iter.size_hint();
37
let length = upper.unwrap_or(lower);
38
39
let mut spawner = BundleSpawner::new::<I::Item>(world, change_tick);
40
spawner.reserve_storage(length);
41
let allocator = spawner.allocator().alloc_many(length as u32);
42
43
Self {
44
inner: iter,
45
allocator,
46
spawner,
47
caller,
48
}
49
}
50
}
51
52
impl<I> Drop for SpawnBatchIter<'_, I>
53
where
54
I: Iterator,
55
I::Item: Bundle<Effect: NoBundleEffect>,
56
{
57
fn drop(&mut self) {
58
// Iterate through self in order to spawn remaining bundles.
59
for _ in &mut *self {}
60
// Apply any commands from those operations.
61
// SAFETY: `self.spawner` will be dropped immediately after this call.
62
unsafe { self.spawner.flush_commands() };
63
}
64
}
65
66
impl<I> Iterator for SpawnBatchIter<'_, I>
67
where
68
I: Iterator,
69
I::Item: Bundle<Effect: NoBundleEffect>,
70
{
71
type Item = Entity;
72
73
fn next(&mut self) -> Option<Entity> {
74
let bundle = self.inner.next()?;
75
move_as_ptr!(bundle);
76
Some(if let Some(bulk) = self.allocator.next() {
77
// SAFETY: bundle matches spawner type and we just allocated it
78
unsafe {
79
self.spawner.spawn_at(bulk, bundle, self.caller);
80
}
81
bulk
82
} else {
83
// SAFETY: bundle matches spawner type
84
unsafe { self.spawner.spawn(bundle, self.caller) }
85
})
86
}
87
88
fn size_hint(&self) -> (usize, Option<usize>) {
89
self.inner.size_hint()
90
}
91
}
92
93
impl<I, T> ExactSizeIterator for SpawnBatchIter<'_, I>
94
where
95
I: ExactSizeIterator<Item = T>,
96
T: Bundle<Effect: NoBundleEffect>,
97
{
98
fn len(&self) -> usize {
99
self.inner.len()
100
}
101
}
102
103
impl<I, T> FusedIterator for SpawnBatchIter<'_, I>
104
where
105
I: FusedIterator<Item = T>,
106
T: Bundle<Effect: NoBundleEffect>,
107
{
108
}
109
110
// SAFETY: Newly spawned entities are unique.
111
unsafe impl<I: Iterator, T> EntitySetIterator for SpawnBatchIter<'_, I>
112
where
113
I: FusedIterator<Item = T>,
114
T: Bundle<Effect: NoBundleEffect>,
115
{
116
}
117
118