Skip to main content

appcore_render/
scene_commands.rs

1// =============================================================================
2//        #######
3//     ###       ###     F: scene_commands.rs
4//    ##   ## ##   ##    P: AppCore-Runtime
5//         ## ##
6//                       C: 2026/10/14 16:59:22 by dnettoRaw
7//    ##   ## ##   ##    U: 2026/10/15 10:24:40 by dnettoRaw
8//      ###########      S: 0.1.0-alpha.1
9// =============================================================================
10
11use crate::{scene_storage::reserved, EntityId, RenderError, SceneWorld, Velocity};
12/// Deferred structural operations, applied only when mutable world ownership is available.
13#[derive(Debug, Clone, Copy)]
14pub enum SceneCommand {
15    /// Migrate to/from the velocity archetype without changing identity.
16    SetVelocity(EntityId, Option<Velocity>),
17    /// Remove one live entity; stale/foreign identities return a controlled error.
18    Despawn(EntityId),
19}
20/// Independent bounded structural queue. Application owns ordering and frame boundaries.
21pub struct SceneCommands {
22    commands: Vec<SceneCommand>,
23    capacity: usize,
24}
25impl SceneCommands {
26    /// Reserve 1..256 operations; no workers, timers or automatic application.
27    pub fn new(capacity: usize) -> Result<Self, RenderError> {
28        if !(1..=256).contains(&capacity) {
29            return Err(RenderError::InvalidLimits);
30        }
31        Ok(Self {
32            commands: reserved(capacity)?,
33            capacity,
34        })
35    }
36    /// Queue before world mutation; overflow leaves existing queued operations intact.
37    pub fn push(&mut self, command: SceneCommand) -> Result<(), RenderError> {
38        if self.commands.len() == self.capacity {
39            return Err(RenderError::BudgetExceeded);
40        }
41        self.commands.push(command);
42        Ok(())
43    }
44    /// Apply in order, returning one outcome per command. This batch is explicitly nontransactional:
45    /// an invalid command does not undo earlier effects or discard subsequent commands.
46    /// Outcome allocation is admitted before any mutation; no user callbacks run inside the batch.
47    pub fn apply(
48        self,
49        world: &mut SceneWorld,
50    ) -> Result<Vec<Result<(), RenderError>>, RenderError> {
51        let mut outcomes = reserved(self.commands.len())?;
52        for command in self.commands {
53            outcomes.push(match command {
54                SceneCommand::SetVelocity(entity, value) => world.set_velocity(entity, value),
55                SceneCommand::Despawn(entity) => world.despawn(entity),
56            });
57        }
58        Ok(outcomes)
59    }
60}