use std::any::{Any, TypeId};
use std::fmt;
use crate::access::Access;
use crate::bundle::BundleInfo;
use crate::system::{Env, Sealed, SystemParam};
use crate::{Bundle, Component, EcsError, Entity, World};
#[derive(Clone, Copy, Debug)]
enum Target {
Existing(Entity),
Spawned(usize),
}
enum Op {
Spawn,
SpawnBundle {
lane: usize,
},
Despawn(Target),
Insert {
target: Target,
lane: usize,
},
Remove {
target: Target,
remove: fn(&mut World, Entity) -> Result<(), EcsError>,
},
}
trait Lane: Send {
fn as_any_mut(&mut self) -> &mut dyn Any;
fn reverse(&mut self);
fn insert_next(&mut self, world: &mut World, entity: Option<Entity>) -> Result<(), EcsError>;
fn spawn_next(&mut self, world: &mut World) -> Result<Entity, EcsError>;
fn clear(&mut self);
}
impl<T: Component> Lane for Vec<T> {
fn as_any_mut(&mut self) -> &mut dyn Any {
self
}
fn reverse(&mut self) {
<[T]>::reverse(self);
}
fn insert_next(&mut self, world: &mut World, entity: Option<Entity>) -> Result<(), EcsError> {
match (self.pop(), entity) {
(Some(value), Some(entity)) => lenient(world.insert(entity, value).map(drop)),
_ => Ok(()),
}
}
fn spawn_next(&mut self, world: &mut World) -> Result<Entity, EcsError> {
let entity = world.spawn()?;
self.insert_next(world, Some(entity))?;
Ok(entity)
}
fn clear(&mut self) {
Vec::clear(self);
}
}
struct BundleLane<B>(Vec<B>);
impl<B: Bundle> Lane for BundleLane<B> {
fn as_any_mut(&mut self) -> &mut dyn Any {
self
}
fn reverse(&mut self) {
self.0.reverse();
}
fn insert_next(&mut self, world: &mut World, entity: Option<Entity>) -> Result<(), EcsError> {
match (self.0.pop(), entity) {
(Some(bundle), Some(entity)) => lenient(world.insert_bundle(entity, bundle)),
_ => Ok(()),
}
}
fn spawn_next(&mut self, world: &mut World) -> Result<Entity, EcsError> {
match self.0.pop() {
Some(bundle) => world.spawn_bundle(bundle),
None => world.spawn(),
}
}
fn clear(&mut self) {
self.0.clear();
}
}
fn lenient(result: Result<(), EcsError>) -> Result<(), EcsError> {
match result {
Err(EcsError::NoSuchEntity { .. }) => Ok(()),
other => other,
}
}
fn remove<T: Component>(world: &mut World, entity: Entity) -> Result<(), EcsError> {
world.remove::<T>(entity).map(drop)
}
#[doc(hidden)]
#[derive(Default)]
pub struct CommandQueue {
ops: Vec<Op>,
lanes: Vec<(TypeId, Box<dyn Lane>)>,
spawns: usize,
spawned: Vec<Entity>,
}
impl fmt::Debug for CommandQueue {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("CommandQueue")
.field("commands", &self.ops.len())
.finish_non_exhaustive()
}
}
impl CommandQueue {
fn oom(&self) -> EcsError {
EcsError::OutOfMemory {
entities: self.ops.len().saturating_add(1),
}
}
fn push(&mut self, op: Op) -> Result<(), EcsError> {
self.ops.try_reserve(1).map_err(|_| self.oom())?;
self.ops.push(op);
Ok(())
}
fn spawn(&mut self) -> Result<Target, EcsError> {
self.push(Op::Spawn)?;
let target = Target::Spawned(self.spawns);
self.spawns = self.spawns.saturating_add(1);
Ok(target)
}
fn lane(
&mut self,
ty: TypeId,
new: impl FnOnce() -> Result<Box<dyn Lane>, EcsError>,
) -> Result<usize, EcsError> {
if let Some(lane) = self.lanes.iter().position(|(t, _)| *t == ty) {
return Ok(lane);
}
self.lanes.try_reserve(1).map_err(|_| self.oom())?;
self.lanes.push((ty, new()?));
Ok(self.lanes.len().saturating_sub(1))
}
fn values<L: 'static>(&mut self, lane: usize) -> Result<&mut L, EcsError> {
self.lanes
.get_mut(lane)
.and_then(|(_, lane)| lane.as_any_mut().downcast_mut::<L>())
.ok_or(EcsError::CapacityExhausted)
}
fn insert<T: Component>(&mut self, target: Target, value: T) -> Result<(), EcsError> {
let lane = self.lane(TypeId::of::<T>(), || Ok(Box::new(Vec::<T>::new())))?;
self.ops.try_reserve(1).map_err(|_| self.oom())?;
let oom = self.oom();
let values = self.values::<Vec<T>>(lane)?;
values.try_reserve(1).map_err(|_| oom)?;
values.push(value);
self.ops.push(Op::Insert { target, lane });
Ok(())
}
fn bundle<B: Bundle>(
&mut self,
bundle: B,
op: impl FnOnce(usize) -> Op,
) -> Result<(), EcsError> {
let entities = self.ops.len().saturating_add(1);
let lane = self.lane(TypeId::of::<BundleLane<B>>(), || {
BundleInfo::of::<B>(entities)?;
Ok(Box::new(BundleLane::<B>(Vec::new())))
})?;
self.ops.try_reserve(1).map_err(|_| self.oom())?;
let oom = self.oom();
let values = &mut self.values::<BundleLane<B>>(lane)?.0;
values.try_reserve(1).map_err(|_| oom)?;
values.push(bundle);
self.ops.push(op(lane));
Ok(())
}
fn spawn_bundle<B: Bundle>(&mut self, bundle: B) -> Result<Target, EcsError> {
self.bundle(bundle, |lane| Op::SpawnBundle { lane })?;
let target = Target::Spawned(self.spawns);
self.spawns = self.spawns.saturating_add(1);
Ok(target)
}
fn insert_bundle<B: Bundle>(&mut self, target: Target, bundle: B) -> Result<(), EcsError> {
self.bundle(bundle, |lane| Op::Insert { target, lane })
}
fn remove<T: Component>(&mut self, target: Target) -> Result<(), EcsError> {
self.push(Op::Remove {
target,
remove: remove::<T>,
})
}
fn len(&self) -> usize {
self.ops.len()
}
pub(crate) fn apply(&mut self, world: &mut World) -> Result<(), EcsError> {
let result = self.apply_all(world);
self.clear();
result
}
fn apply_all(&mut self, world: &mut World) -> Result<(), EcsError> {
let Self {
ops,
lanes,
spawns,
spawned,
} = self;
spawned.clear();
spawned
.try_reserve(*spawns)
.map_err(|_| EcsError::OutOfMemory {
entities: world.len().saturating_add(*spawns),
})?;
for (_, lane) in lanes.iter_mut() {
lane.reverse();
}
let resolve = |spawned: &[Entity], target: Target| match target {
Target::Existing(entity) => Some(entity),
Target::Spawned(n) => spawned.get(n).copied(),
};
for op in ops.drain(..) {
match op {
Op::Spawn => spawned.push(world.spawn()?),
Op::SpawnBundle { lane } => {
let entity = match lanes.get_mut(lane) {
Some((_, lane)) => lane.spawn_next(world)?,
None => world.spawn()?,
};
spawned.push(entity);
}
Op::Despawn(target) => {
if let Some(entity) = resolve(spawned, target) {
lenient(world.despawn(entity))?;
}
}
Op::Insert { target, lane } => {
if let Some((_, lane)) = lanes.get_mut(lane) {
lane.insert_next(world, resolve(spawned, target))?;
}
}
Op::Remove { target, remove } => {
if let Some(entity) = resolve(spawned, target) {
lenient(remove(world, entity))?;
}
}
}
}
Ok(())
}
pub(crate) fn clear(&mut self) {
self.ops.clear();
for (_, lane) in &mut self.lanes {
lane.clear();
}
self.spawns = 0;
self.spawned.clear();
}
}
pub struct Commands<'s> {
queue: &'s mut CommandQueue,
}
impl fmt::Debug for Commands<'_> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("Commands")
.field("commands", &self.queue.len())
.finish()
}
}
impl Commands<'_> {
pub fn spawn(&mut self) -> Result<EntityCommands<'_>, EcsError> {
let target = self.queue.spawn()?;
Ok(EntityCommands {
queue: self.queue,
target,
})
}
pub fn spawn_bundle<B: Bundle>(&mut self, bundle: B) -> Result<EntityCommands<'_>, EcsError> {
let target = self.queue.spawn_bundle(bundle)?;
Ok(EntityCommands {
queue: self.queue,
target,
})
}
pub fn entity(&mut self, entity: Entity) -> EntityCommands<'_> {
EntityCommands {
queue: self.queue,
target: Target::Existing(entity),
}
}
pub fn despawn(&mut self, entity: Entity) -> Result<(), EcsError> {
self.queue.push(Op::Despawn(Target::Existing(entity)))
}
pub fn insert<T: Component>(&mut self, entity: Entity, value: T) -> Result<(), EcsError> {
self.queue.insert(Target::Existing(entity), value)
}
pub fn insert_bundle<B: Bundle>(&mut self, entity: Entity, bundle: B) -> Result<(), EcsError> {
self.queue.insert_bundle(Target::Existing(entity), bundle)
}
pub fn remove<T: Component>(&mut self, entity: Entity) -> Result<(), EcsError> {
self.queue.remove::<T>(Target::Existing(entity))
}
#[must_use]
pub fn len(&self) -> usize {
self.queue.len()
}
#[must_use]
pub fn is_empty(&self) -> bool {
self.queue.len() == 0
}
}
pub struct EntityCommands<'a> {
queue: &'a mut CommandQueue,
target: Target,
}
impl fmt::Debug for EntityCommands<'_> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("EntityCommands")
.field("target", &self.target)
.finish_non_exhaustive()
}
}
impl EntityCommands<'_> {
#[must_use]
pub const fn id(&self) -> Option<Entity> {
match self.target {
Target::Existing(entity) => Some(entity),
Target::Spawned(_) => None,
}
}
pub fn insert<T: Component>(&mut self, value: T) -> Result<&mut Self, EcsError> {
self.queue.insert(self.target, value)?;
Ok(self)
}
pub fn insert_bundle<B: Bundle>(&mut self, bundle: B) -> Result<&mut Self, EcsError> {
self.queue.insert_bundle(self.target, bundle)?;
Ok(self)
}
pub fn remove<T: Component>(&mut self) -> Result<&mut Self, EcsError> {
self.queue.remove::<T>(self.target)?;
Ok(self)
}
pub fn despawn(self) -> Result<(), EcsError> {
self.queue.push(Op::Despawn(self.target))
}
}
impl Sealed for Commands<'_> {}
impl SystemParam for Commands<'_> {
type State = CommandQueue;
type Item<'w, 's> = Commands<'s>;
fn init() -> Result<Self::State, EcsError> {
Ok(CommandQueue::default())
}
fn declare(_: &mut Access) -> Result<(), EcsError> {
Ok(())
}
fn fetch<'w, 's>(
state: &'s mut Self::State,
_: Env<'w>,
) -> Result<Self::Item<'w, 's>, EcsError> {
Ok(Commands { queue: state })
}
fn apply(state: &mut Self::State, world: &mut World) -> Result<(), EcsError> {
state.apply(world)
}
fn discard(state: &mut Self::State) {
state.clear();
}
}
impl fmt::Debug for Op {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Self::Spawn => f.write_str("Spawn"),
Self::SpawnBundle { .. } => f.write_str("SpawnBundle"),
Self::Despawn(target) => write!(f, "Despawn({target:?})"),
Self::Insert { target, .. } => write!(f, "Insert({target:?})"),
Self::Remove { target, .. } => write!(f, "Remove({target:?})"),
}
}
}
#[cfg(test)]
mod tests {
use super::*;
#[derive(Debug, PartialEq)]
struct A(u32);
#[derive(Debug, PartialEq)]
struct B(u32);
#[test]
fn commands_apply_in_order_and_skip_dead_entities() {
let mut world = World::new();
let old = world.spawn().unwrap();
let gone = world.spawn().unwrap();
world.despawn(gone).unwrap();
let mut queue = CommandQueue::default();
let mut commands = Commands { queue: &mut queue };
commands
.spawn()
.unwrap()
.insert(A(1))
.unwrap()
.insert(B(2))
.unwrap();
commands.insert(old, A(3)).unwrap();
commands.insert(gone, A(4)).unwrap();
commands.despawn(gone).unwrap();
commands.remove::<B>(gone).unwrap();
let mut second = commands.spawn().unwrap();
assert_eq!(second.id(), None);
second.insert(A(5)).unwrap().remove::<A>().unwrap();
second.despawn().unwrap();
commands.entity(old).insert(A(6)).unwrap();
assert_eq!(commands.entity(old).id(), Some(old));
assert_eq!(commands.len(), 12);
assert!(format!("{commands:?}").contains("12"));
queue.apply(&mut world).unwrap();
assert_eq!(queue.len(), 0);
assert_eq!(world.len(), 2);
assert_eq!(world.get::<A>(old), Some(&A(6)));
let mut query = crate::Query::<(Entity, &A, &B)>::new().unwrap();
let rows: Vec<_> = query
.iter(&world)
.unwrap()
.map(|(_, a, b)| (a.0, b.0))
.collect();
assert_eq!(rows, [(1, 2)]);
Commands { queue: &mut queue }.insert(old, A(7)).unwrap();
queue.clear();
queue.apply(&mut world).unwrap();
assert_eq!(world.get::<A>(old), Some(&A(6)));
assert!(format!("{queue:?}").starts_with("CommandQueue"));
assert_eq!(format!("{:?}", Op::Spawn), "Spawn");
}
#[test]
fn bundles_are_deferred_like_components() {
let mut world = World::new();
let old = world.spawn().unwrap();
let mut queue = CommandQueue::default();
let mut commands = Commands { queue: &mut queue };
commands
.spawn_bundle((A(1), B(2)))
.unwrap()
.insert_bundle((A(3),))
.unwrap();
commands.insert_bundle(old, (B(4), A(5))).unwrap();
commands.insert(old, (A(6), B(7))).unwrap();
let dup = commands.spawn_bundle((B(0), B(1))).map(|_| ());
assert_eq!(
dup,
Err(EcsError::DuplicateComponent {
component: std::any::type_name::<B>()
})
);
assert_eq!(commands.len(), 4);
assert_eq!(format!("{:?}", Op::SpawnBundle { lane: 0 }), "SpawnBundle");
queue.apply(&mut world).unwrap();
assert_eq!(world.len(), 2);
assert_eq!(world.get::<A>(old), Some(&A(5)));
assert_eq!(world.get::<(A, B)>(old), Some(&(A(6), B(7))));
let mut query = crate::Query::<(Entity, &A, &B)>::new().unwrap();
let rows: Vec<_> = query
.iter(&world)
.unwrap()
.filter(|(e, _, _)| *e != old)
.map(|(_, a, b)| (a.0, b.0))
.collect();
assert_eq!(rows, [(3, 2)]);
}
}