1use core::fmt;
2
3use alloc::{boxed::Box, format, vec::Vec};
4use anyhow::Context;
5
6use crate::{
7 buffer::MultiComponentBuffer,
8 component::{ComponentDesc, ComponentValue},
9 writer::{MissingDyn, SingleComponentWriter, WriteDedupDyn},
10 BatchSpawn, Component, Entity, EntityBuilder, World,
11};
12
13type DeferFn = Box<dyn Fn(&mut World) -> anyhow::Result<()> + Send + Sync>;
14
15enum Command {
17 Spawn(EntityBuilder),
19 AppendTo(EntityBuilder, Entity),
20 SpawnAt(EntityBuilder, Entity),
21 SpawnBatch(BatchSpawn),
23 SpawnBatchAt(BatchSpawn, Vec<Entity>),
24 Set {
26 id: Entity,
27 desc: ComponentDesc,
28 offset: usize,
29 },
30 SetDedup {
31 id: Entity,
32 desc: ComponentDesc,
33 offset: usize,
34 cmp: unsafe fn(*const u8, *const u8) -> bool,
35 },
36 SetMissing {
37 id: Entity,
38 desc: ComponentDesc,
39 offset: usize,
40 },
41 Despawn(Entity),
43 Remove {
45 id: Entity,
46 desc: ComponentDesc,
47 },
48
49 Defer(DeferFn),
51}
52
53impl fmt::Debug for Command {
54 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
55 match self {
56 Self::Spawn(v) => f.debug_tuple("Spawn").field(v).finish(),
57 Self::SpawnAt(id, v) => f.debug_tuple("SpawnAt").field(&v).field(&id).finish(),
58 Self::AppendTo(id, v) => f.debug_tuple("AppendTo").field(&v).field(&id).finish(),
59 Self::SpawnBatch(batch) => f.debug_tuple("SpawnBatch").field(batch).finish(),
60 Self::SpawnBatchAt(batch, ids) => f
61 .debug_tuple("SpawnBatchAt")
62 .field(&batch)
63 .field(&ids.len())
64 .finish(),
65 Self::Set { id, desc, offset } => f
66 .debug_struct("Set")
67 .field("id", id)
68 .field("desc", desc)
69 .field("offset", offset)
70 .finish(),
71 Self::SetDedup {
72 id,
73 desc,
74 offset,
75 cmp: _,
76 } => f
77 .debug_struct("SetDedup")
78 .field("id", id)
79 .field("desc", desc)
80 .field("offset", offset)
81 .finish(),
82 Self::SetMissing { id, desc, offset } => f
83 .debug_struct("SetMissing")
84 .field("id", id)
85 .field("desc", desc)
86 .field("offset", offset)
87 .finish(),
88 Self::Despawn(arg0) => f.debug_tuple("Despawn").field(arg0).finish(),
89 Self::Remove {
90 id,
91 desc: component,
92 } => f
93 .debug_struct("Remove")
94 .field("id", id)
95 .field("component", component)
96 .finish(),
97 Self::Defer(_) => f.debug_tuple("Defer").field(&"...").finish(),
98 }
99 }
100}
101
102#[derive(Default)]
106pub struct CommandBuffer {
107 inserts: MultiComponentBuffer,
108 commands: Vec<Command>,
109}
110
111impl fmt::Debug for CommandBuffer {
112 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
113 f.debug_struct("CommandBuffer")
114 .field("commands", &self.commands)
115 .finish()
116 }
117}
118
119unsafe impl Send for CommandBuffer {}
121unsafe impl Sync for CommandBuffer {}
122
123impl CommandBuffer {
124 pub fn new() -> Self {
126 Self::default()
127 }
128
129 pub fn set<T: ComponentValue>(
131 &mut self,
132 id: Entity,
133 component: Component<T>,
134 value: T,
135 ) -> &mut Self {
136 let offset = self.inserts.push(value);
137 self.commands.push(Command::Set {
138 id,
139 desc: component.desc(),
140 offset,
141 });
142
143 self
144 }
145
146 pub fn set_opt<T: ComponentValue>(
148 &mut self,
149 id: Entity,
150 component: Component<T>,
151 value: Option<T>,
152 ) -> &mut Self {
153 if let Some(value) = value {
154 self.set(id, component, value);
155 }
156 self
157 }
158
159 pub fn set_dedup<T: ComponentValue + PartialEq>(
163 &mut self,
164 id: Entity,
165 component: Component<T>,
166 value: T,
167 ) -> &mut Self {
168 let offset = self.inserts.push(value);
169 unsafe fn cmp<T: PartialEq>(a: *const u8, b: *const u8) -> bool {
170 let a = &*(a as *const T);
171 let b = &*(b as *const T);
172
173 a == b
174 }
175 self.commands.push(Command::SetDedup {
176 id,
177 desc: component.desc(),
178 offset,
179 cmp: cmp::<T>,
180 });
181
182 self
183 }
184
185 pub fn set_missing<T: ComponentValue>(
189 &mut self,
190 id: Entity,
191 component: Component<T>,
192 value: T,
193 ) -> &mut Self {
194 let offset = self.inserts.push(value);
195 self.commands.push(Command::SetMissing {
196 id,
197 desc: component.desc(),
198 offset,
199 });
200
201 self
202 }
203 pub fn remove<T: ComponentValue>(&mut self, id: Entity, component: Component<T>) -> &mut Self {
207 self.commands.push(Command::Remove {
208 id,
209 desc: component.desc(),
210 });
211
212 self
213 }
214
215 pub fn spawn(&mut self, entity: impl Into<EntityBuilder>) -> &mut Self {
217 self.commands.push(Command::Spawn(entity.into()));
218
219 self
220 }
221
222 pub fn spawn_at(&mut self, id: Entity, entity: impl Into<EntityBuilder>) -> &mut Self {
224 self.commands.push(Command::SpawnAt(entity.into(), id));
225
226 self
227 }
228
229 pub fn append_to(&mut self, id: Entity, entity: impl Into<EntityBuilder>) -> &mut Self {
231 self.commands.push(Command::AppendTo(entity.into(), id));
232
233 self
234 }
235
236 pub fn spawn_batch(&mut self, chunk: impl Into<BatchSpawn>) -> &mut Self {
238 self.commands.push(Command::SpawnBatch(chunk.into()));
239
240 self
241 }
242
243 pub fn spawn_batch_at(&mut self, ids: Vec<Entity>, chunk: impl Into<BatchSpawn>) -> &mut Self {
245 self.commands.push(Command::SpawnBatchAt(chunk.into(), ids));
246
247 self
248 }
249
250 pub fn despawn(&mut self, id: Entity) -> &mut Self {
252 self.commands.push(Command::Despawn(id));
253 self
254 }
255
256 pub fn defer(
260 &mut self,
261 func: impl Fn(&mut World) -> anyhow::Result<()> + Send + Sync + 'static,
262 ) -> &mut Self {
263 self.commands.push(Command::Defer(Box::new(func)));
264 self
265 }
266
267 pub fn apply(&mut self, world: &mut World) -> anyhow::Result<()> {
270 for cmd in self.commands.drain(..) {
271 match cmd {
272 Command::Spawn(mut entity) => {
273 entity.spawn(world);
274 }
275 Command::SpawnAt(mut entity, id) => {
276 entity
277 .spawn_at(world, id)
278 .map_err(|v| v.into_anyhow())
279 .context("Failed to spawn entity")?;
280 }
281 Command::AppendTo(mut entity, id) => {
282 entity
283 .append_to(world, id)
284 .map_err(|v| v.into_anyhow())
285 .context("Failed to append to entity")?;
286 }
287 Command::SpawnBatch(mut batch) => {
288 batch.spawn(world);
289 }
290 Command::SpawnBatchAt(mut batch, ids) => {
291 batch
292 .spawn_at(world, &ids)
293 .map_err(|v| v.into_anyhow())
294 .context("Failed to spawn entity")?;
295 }
296 Command::Set { id, desc, offset } => unsafe {
297 let value = self.inserts.take_dyn(offset);
298 world
299 .set_dyn(id, desc, value)
300 .map_err(|v| v.into_anyhow())
301 .with_context(|| format!("Failed to set component {}", desc.name()))?;
302 },
303 Command::SetDedup {
304 id,
305 desc,
306 offset,
307 cmp,
308 } => unsafe {
309 let value = self.inserts.take_dyn(offset);
310 world
311 .set_with_writer(
312 id,
313 SingleComponentWriter::new(desc, WriteDedupDyn { value, cmp }),
314 )
315 .map_err(|v| v.into_anyhow())
316 .with_context(|| format!("Failed to set component {}", desc.name()))?;
317 },
318 Command::SetMissing { id, desc, offset } => unsafe {
319 let value = self.inserts.take_dyn(offset);
320 world
321 .set_with_writer(id, SingleComponentWriter::new(desc, MissingDyn { value }))
322 .map_err(|v| v.into_anyhow())
323 .with_context(|| format!("Failed to set component {}", desc.name()))?;
324 },
325 Command::Despawn(id) => world
326 .despawn(id)
327 .map_err(|v| v.into_anyhow())
328 .context("Failed to despawn entity")?,
329 Command::Remove { id, desc } => world
330 .remove_dyn(id, desc)
331 .map_err(|v| v.into_anyhow())
332 .with_context(|| format!("Failed to remove component {}", desc.name()))?,
333 Command::Defer(func) => {
334 func(world).context("Failed to execute deferred function")?
335 }
336 }
337 }
338
339 self.inserts.clear();
340
341 Ok(())
342 }
343
344 pub fn clear(&mut self) {
347 self.inserts.clear();
348 self.commands.clear()
349 }
350}
351
352#[cfg(test)]
353mod tests {
354 use crate::{component, FetchExt, Query};
355
356 use super::*;
357
358 #[test]
359 fn set_missing() {
360 use alloc::string::String;
361 use alloc::string::ToString;
362
363 component! {
364 a: String,
365 }
366
367 let mut world = World::new();
368 let mut cmd = CommandBuffer::new();
369
370 let mut query = Query::new((a().modified().satisfied(), a().cloned()));
371
372 let id = EntityBuilder::new().spawn(&mut world);
373
374 assert!(query.collect_vec(&world).is_empty());
375
376 cmd.set_missing(id, a(), "Foo".into())
377 .set_missing(id, a(), "Bar".into());
378
379 cmd.apply(&mut world).unwrap();
380
381 assert_eq!(query.collect_vec(&world), [(true, "Foo".to_string())]);
382 assert_eq!(query.collect_vec(&world), [(false, "Foo".to_string())]);
383
384 cmd.set_missing(id, a(), "Baz".into());
385 cmd.apply(&mut world).unwrap();
386
387 assert_eq!(query.collect_vec(&world), [(false, "Foo".to_string())]);
388 }
389
390 #[test]
391 fn set_dedup() {
392 use alloc::string::String;
393 use alloc::string::ToString;
394
395 component! {
396 a: String,
397 }
398
399 let mut world = World::new();
400 let mut cmd = CommandBuffer::new();
401
402 let mut query = Query::new((a().modified().satisfied(), a().cloned()));
403
404 let id = EntityBuilder::new().spawn(&mut world);
405
406 assert!(query.collect_vec(&world).is_empty());
407
408 cmd.set_dedup(id, a(), "Foo".into())
409 .set_dedup(id, a(), "Bar".into());
410
411 cmd.apply(&mut world).unwrap();
412
413 assert_eq!(query.collect_vec(&world), [(true, "Bar".to_string())]);
414 assert_eq!(query.collect_vec(&world), [(false, "Bar".to_string())]);
415
416 cmd.set_dedup(id, a(), "Baz".into());
417 cmd.apply(&mut world).unwrap();
418
419 assert_eq!(query.collect_vec(&world), [(true, "Baz".to_string())]);
420
421 cmd.set_dedup(id, a(), "Baz".into());
422 cmd.apply(&mut world).unwrap();
423 assert_eq!(query.collect_vec(&world), [(false, "Baz".to_string())]);
424 }
425}