use std::{cell::RefMut, collections::VecDeque, mem, ptr::{self, NonNull}}; use unique::Unique; use crate::{system::FnArgFetcher, Access, Bundle, Entities, Entity, World}; pub trait Command { fn run(self, world: &mut World) -> anyhow::Result<()>; } impl Command for F where F: FnOnce(&mut World) -> anyhow::Result<()> { fn run(self, world: &mut World) -> anyhow::Result<()> { self(world) } } type RunCommand = unsafe fn(cmd: Unique<()>, world: &mut World) -> anyhow::Result<()>; #[derive(Default)] pub struct CommandQueue(VecDeque<(RunCommand, Unique<()>)>); pub struct Commands<'a, 'b> { queue: &'b mut CommandQueue, entities: &'a mut Entities, } impl<'a, 'b> Commands<'a, 'b> { pub fn new(queue: &'b mut CommandQueue, world: &'a mut World) -> Self { Self { queue, entities: &mut world.entities, } } /// Add a command to the end of the command queue pub fn add(&mut self, mut cmd: C) { // get an owned pointer to the command, then forget it to ensure its destructor isn't ran let ptr = Unique::from(&mut cmd).cast::<()>(); mem::forget(cmd); let run_fn = |cmd_ptr: Unique<()>, world: &mut World| unsafe { let cmd = cmd_ptr.cast::(); let cmd = ptr::read(cmd.as_ptr()); cmd.run(world)?; Ok(()) }; self.queue.0.push_back((run_fn, ptr)); } pub fn spawn(&mut self, mut bundle: B) -> Entity { let e = self.entities.reserve(); let bundle_ptr = Unique::from(&mut bundle); mem::forget(bundle); //let bundle_box = Box::new(bundle); self.add(move |world: &mut World| { let bundle = unsafe { ptr::read(bundle_ptr.as_ptr()) }; world.spawn_into(e, bundle); Ok(()) }); e } /// Execute all commands in the queue, in order of insertion pub fn execute(&mut self, world: &mut World) -> anyhow::Result<()> { while let Some((cmd_fn, cmd_ptr)) = self.queue.0.pop_front() { unsafe { cmd_fn(cmd_ptr, world)?; } } Ok(()) } } impl FnArgFetcher for Commands<'_, '_> { type State = CommandQueue; type Arg<'a, 'state> = Commands<'a, 'state>; fn world_access(&self) -> Access { Access::Write } unsafe fn get<'a, 'state>(state: &'state mut Self::State, mut world_ptr: ptr::NonNull) -> Self::Arg<'a, 'state> { let world = world_ptr.as_mut(); Commands::new(state, world) } fn create_state(_: NonNull) -> Self::State { CommandQueue::default() } fn apply_deferred<'a>(mut state: Self::State, mut world_ptr: NonNull) { let world = unsafe { world_ptr.as_mut() }; let mut cmds = Commands::new(&mut state, world); // safety: Commands has a mut borrow to entities in the world let world = unsafe { world_ptr.as_mut() }; cmds.execute(world).unwrap() } } pub fn execute_deferred_commands(world: &mut World, mut commands: RefMut) -> anyhow::Result<()> { commands.execute(world)?; Ok(()) }