1use core::any::TypeId;
2use core::mem;
3use core::ops::Range;
4use core::ptr::{self, NonNull};
5
6use crate::alloc::alloc::{alloc, dealloc, Layout};
7use crate::alloc::vec::Vec;
8use crate::archetype::TypeInfo;
9use crate::{align, DynamicBundle};
10use crate::{Bundle, Entity};
11use crate::{Component, World};
12
13pub struct CommandBuffer {
27 cmds: Vec<Cmd>,
28 storage: NonNull<u8>,
29 layout: Layout,
30 cursor: usize,
31 components: Vec<ComponentInfo>,
32 ids: Vec<TypeId>,
33}
34
35impl CommandBuffer {
36 pub fn new() -> Self {
38 Self::default()
39 }
40
41 unsafe fn grow(
42 min_size: usize,
43 cursor: usize,
44 align: usize,
45 storage: NonNull<u8>,
46 ) -> (NonNull<u8>, Layout) {
47 let layout = Layout::from_size_align(min_size.next_power_of_two().max(64), align).unwrap();
48 let new_storage = NonNull::new_unchecked(alloc(layout));
49 ptr::copy_nonoverlapping(storage.as_ptr(), new_storage.as_ptr(), cursor);
50 (new_storage, layout)
51 }
52
53 unsafe fn add_inner(&mut self, ptr: *mut u8, ty: TypeInfo) {
54 let offset = align(self.cursor, ty.layout().align());
55 let end = offset + ty.layout().size();
56
57 if end > self.layout.size() || ty.layout().align() > self.layout.align() {
58 let new_align = self.layout.align().max(ty.layout().align());
59 let (new_storage, new_layout) = Self::grow(end, self.cursor, new_align, self.storage);
60 if self.layout.size() != 0 {
61 dealloc(self.storage.as_ptr(), self.layout);
62 }
63 self.storage = new_storage;
64 self.layout = new_layout;
65 }
66
67 let addr = self.storage.as_ptr().add(offset);
68 ptr::copy_nonoverlapping(ptr, addr, ty.layout().size());
69 self.components.push(ComponentInfo { ty, offset });
70 self.cursor = end;
71 }
72
73 pub fn insert(&mut self, entity: Entity, components: impl DynamicBundle) {
79 let first_component = self.components.len();
80 unsafe {
81 components.put(|ptr, ty| self.add_inner(ptr, ty));
82 }
83 self.components[first_component..].sort_unstable_by_key(|c| c.ty);
84 self.cmds.push(Cmd::SpawnOrInsert(EntityIndex {
85 entity: Some(entity),
86 components: first_component..self.components.len(),
87 }));
88 }
89
90 pub fn insert_one(&mut self, entity: Entity, component: impl Component) {
94 self.insert(entity, (component,));
95 }
96
97 pub fn remove<T: Bundle + 'static>(&mut self, ent: Entity) {
101 fn remove_bundle_and_ignore_result<T: Bundle + 'static>(world: &mut World, ents: Entity) {
102 let _ = world.remove::<T>(ents);
103 }
104 self.cmds.push(Cmd::Remove(RemovedComps {
105 remove: remove_bundle_and_ignore_result::<T>,
106 entity: ent,
107 }));
108 }
109
110 pub fn remove_one<T: Component>(&mut self, ent: Entity) {
114 self.remove::<(T,)>(ent);
115 }
116
117 pub fn despawn(&mut self, entity: Entity) {
119 self.cmds.push(Cmd::Despawn(entity));
120 }
121
122 pub fn spawn(&mut self, components: impl DynamicBundle) {
127 let first_component = self.components.len();
128 unsafe {
129 components.put(|ptr, ty| self.add_inner(ptr, ty));
130 }
131 self.components[first_component..].sort_unstable_by_key(|c| c.ty);
132 self.cmds.push(Cmd::SpawnOrInsert(EntityIndex {
133 entity: None,
134 components: first_component..self.components.len(),
135 }));
136 }
137
138 pub fn run_on(&mut self, world: &mut World) {
140 for i in 0..self.cmds.len() {
141 match mem::replace(&mut self.cmds[i], Cmd::Despawn(Entity::DANGLING)) {
142 Cmd::SpawnOrInsert(entity) => {
143 let components = self.build(entity.components);
144 match entity.entity {
145 Some(entity) => {
146 let _ = world.insert(entity, components);
148 }
149 None => {
150 world.spawn(components);
151 }
152 }
153 }
154 Cmd::Remove(remove) => {
155 (remove.remove)(world, remove.entity);
156 }
157 Cmd::Despawn(entity) => {
158 let _ = world.despawn(entity);
159 }
160 }
161 }
162 self.components.clear();
164
165 self.clear();
166 }
167
168 fn build(&mut self, components: Range<usize>) -> RecordedEntity<'_> {
169 self.ids.clear();
170 self.ids.extend(
171 self.components[components.clone()]
172 .iter()
173 .map(|x| x.ty.id()),
174 );
175 RecordedEntity {
176 cmd: self,
177 components,
178 }
179 }
180
181 pub fn clear(&mut self) {
183 self.ids.clear();
184 self.cursor = 0;
185 for info in self.components.drain(..) {
186 unsafe {
187 info.ty.drop(self.storage.as_ptr().add(info.offset));
188 }
189 }
190 self.cmds.clear();
191 }
192}
193
194unsafe impl Send for CommandBuffer {}
195unsafe impl Sync for CommandBuffer {}
196
197impl Drop for CommandBuffer {
198 fn drop(&mut self) {
199 self.clear();
200 if self.layout.size() != 0 {
201 unsafe {
202 dealloc(self.storage.as_ptr(), self.layout);
203 }
204 }
205 }
206}
207
208impl Default for CommandBuffer {
209 fn default() -> Self {
211 Self {
212 cmds: Vec::new(),
213 storage: NonNull::dangling(),
214 layout: Layout::from_size_align(0, 8).unwrap(),
215 cursor: 0,
216 components: Vec::new(),
217 ids: Vec::new(),
218 }
219 }
220}
221
222struct RecordedEntity<'a> {
225 cmd: &'a mut CommandBuffer,
226 components: Range<usize>,
227}
228
229unsafe impl DynamicBundle for RecordedEntity<'_> {
230 fn with_ids<T>(&self, f: impl FnOnce(&[TypeId]) -> T) -> T {
231 f(&self.cmd.ids)
232 }
233
234 fn type_info(&self) -> Vec<TypeInfo> {
235 self.cmd.components[self.components.clone()]
236 .iter()
237 .map(|x| x.ty)
238 .collect()
239 }
240
241 unsafe fn put(mut self, mut f: impl FnMut(*mut u8, TypeInfo)) {
242 let components = mem::replace(&mut self.components, 0..0);
244 for info in &self.cmd.components[components] {
245 let ptr = self.cmd.storage.as_ptr().add(info.offset);
246 f(ptr, info.ty);
247 }
248 }
249}
250
251impl Drop for RecordedEntity<'_> {
252 fn drop(&mut self) {
253 unsafe {
256 for info in &self.cmd.components[self.components.clone()] {
257 info.ty.drop(self.cmd.storage.as_ptr().add(info.offset));
258 }
259 }
260 }
261}
262
263struct ComponentInfo {
265 ty: TypeInfo,
266 offset: usize,
268}
269
270struct EntityIndex {
272 entity: Option<Entity>,
273 components: Range<usize>,
278}
279
280struct RemovedComps {
282 remove: fn(&mut World, Entity),
283 entity: Entity,
284}
285
286enum Cmd {
288 SpawnOrInsert(EntityIndex),
289 Remove(RemovedComps),
290 Despawn(Entity),
291}
292
293#[cfg(test)]
294mod tests {
295 use super::*;
296
297 #[test]
298 fn populate_archetypes() {
299 let mut world = World::new();
300 let mut buffer = CommandBuffer::new();
301 let ent = world.reserve_entity();
302 let enta = world.reserve_entity();
303 let entb = world.reserve_entity();
304 let entc = world.reserve_entity();
305 buffer.insert(ent, (true, "a"));
306 buffer.insert(entc, (true, "a"));
307 buffer.insert(enta, (1, 1.0));
308 buffer.insert(entb, (1.0, "a"));
309 buffer.run_on(&mut world);
310 assert_eq!(world.archetypes().len(), 4);
311 }
312
313 #[test]
314 fn failed_insert_regression() {
315 #[derive(Clone)]
318 struct A;
319
320 let mut world = World::new();
321
322 let a = world.spawn((A,));
324 let b = world.spawn((A,));
325
326 world.clear();
328
329 let mut cmd = CommandBuffer::new();
330 cmd.insert_one(a, A);
331 cmd.insert_one(b, A);
332
333 world.spawn_at(a, ());
335
336 cmd.run_on(&mut world);
338
339 assert!(world.satisfies::<&A>(a));
340 }
341
342 #[test]
343 fn insert_then_remove() {
344 let mut world = World::new();
345 let a = world.spawn(());
346 let mut cmd = CommandBuffer::new();
347 cmd.insert_one(a, 42i32);
348 cmd.remove_one::<i32>(a);
349 cmd.run_on(&mut world);
350 assert!(!world.satisfies::<&i32>(a));
351 }
352
353 #[test]
354 fn remove_then_insert() {
355 let mut world = World::new();
356 let a = world.spawn((17i32,));
357 let mut cmd = CommandBuffer::new();
358 cmd.remove_one::<i32>(a);
359 cmd.insert_one(a, 42i32);
360 cmd.run_on(&mut world);
361 assert_eq!(*world.get::<&i32>(a).unwrap(), 42);
362 }
363}