pub use bevy_ecs_macros::MapEntities;
use indexmap::{IndexMap, IndexSet};
use crate::{
entity::{hash_map::EntityHashMap, Entity},
world::World,
};
use alloc::{
collections::{BTreeMap, BTreeSet, VecDeque},
vec::Vec,
};
use bevy_platform::collections::{HashMap, HashSet};
use core::{
hash::{BuildHasher, Hash},
mem,
};
use smallvec::SmallVec;
use super::EntityIndexSet;
pub trait MapEntities {
fn map_entities<E: EntityMapper>(&mut self, entity_mapper: &mut E);
}
impl MapEntities for Entity {
fn map_entities<E: EntityMapper>(&mut self, entity_mapper: &mut E) {
*self = entity_mapper.get_mapped(*self);
}
}
impl<T: MapEntities> MapEntities for Option<T> {
fn map_entities<E: EntityMapper>(&mut self, entity_mapper: &mut E) {
if let Some(entities) = self {
entities.map_entities(entity_mapper);
}
}
}
impl<K: MapEntities + Eq + Hash, V: MapEntities, S: BuildHasher + Default> MapEntities
for HashMap<K, V, S>
{
fn map_entities<E: EntityMapper>(&mut self, entity_mapper: &mut E) {
*self = self
.drain()
.map(|(mut key_entities, mut value_entities)| {
key_entities.map_entities(entity_mapper);
value_entities.map_entities(entity_mapper);
(key_entities, value_entities)
})
.collect();
}
}
impl<T: MapEntities + Eq + Hash, S: BuildHasher + Default> MapEntities for HashSet<T, S> {
fn map_entities<E: EntityMapper>(&mut self, entity_mapper: &mut E) {
*self = self
.drain()
.map(|mut entities| {
entities.map_entities(entity_mapper);
entities
})
.collect();
}
}
impl<K: MapEntities + Eq + Hash, V: MapEntities, S: BuildHasher + Default> MapEntities
for IndexMap<K, V, S>
{
fn map_entities<E: EntityMapper>(&mut self, entity_mapper: &mut E) {
*self = self
.drain(..)
.map(|(mut key_entities, mut value_entities)| {
key_entities.map_entities(entity_mapper);
value_entities.map_entities(entity_mapper);
(key_entities, value_entities)
})
.collect();
}
}
impl<T: MapEntities + Eq + Hash, S: BuildHasher + Default> MapEntities for IndexSet<T, S> {
fn map_entities<E: EntityMapper>(&mut self, entity_mapper: &mut E) {
*self = self
.drain(..)
.map(|mut entities| {
entities.map_entities(entity_mapper);
entities
})
.collect();
}
}
impl MapEntities for EntityIndexSet {
fn map_entities<E: EntityMapper>(&mut self, entity_mapper: &mut E) {
*self = self
.drain(..)
.map(|e| entity_mapper.get_mapped(e))
.collect();
}
}
impl<K: MapEntities + Ord, V: MapEntities> MapEntities for BTreeMap<K, V> {
fn map_entities<E: EntityMapper>(&mut self, entity_mapper: &mut E) {
*self = mem::take(self)
.into_iter()
.map(|(mut key_entities, mut value_entities)| {
key_entities.map_entities(entity_mapper);
value_entities.map_entities(entity_mapper);
(key_entities, value_entities)
})
.collect();
}
}
impl<T: MapEntities + Ord> MapEntities for BTreeSet<T> {
fn map_entities<E: EntityMapper>(&mut self, entity_mapper: &mut E) {
*self = mem::take(self)
.into_iter()
.map(|mut entities| {
entities.map_entities(entity_mapper);
entities
})
.collect();
}
}
impl<T: MapEntities, const N: usize> MapEntities for [T; N] {
fn map_entities<E: EntityMapper>(&mut self, entity_mapper: &mut E) {
for entities in self.iter_mut() {
entities.map_entities(entity_mapper);
}
}
}
impl<T: MapEntities> MapEntities for Vec<T> {
fn map_entities<E: EntityMapper>(&mut self, entity_mapper: &mut E) {
for entities in self.iter_mut() {
entities.map_entities(entity_mapper);
}
}
}
impl<T: MapEntities> MapEntities for VecDeque<T> {
fn map_entities<E: EntityMapper>(&mut self, entity_mapper: &mut E) {
for entities in self.iter_mut() {
entities.map_entities(entity_mapper);
}
}
}
impl<T: MapEntities, A: smallvec::Array<Item = T>> MapEntities for SmallVec<A> {
fn map_entities<E: EntityMapper>(&mut self, entity_mapper: &mut E) {
for entities in self.iter_mut() {
entities.map_entities(entity_mapper);
}
}
}
pub trait EntityMapper {
fn get_mapped(&mut self, source: Entity) -> Entity;
fn set_mapped(&mut self, source: Entity, target: Entity);
}
impl EntityMapper for () {
#[inline]
fn get_mapped(&mut self, source: Entity) -> Entity {
source
}
#[inline]
fn set_mapped(&mut self, _source: Entity, _target: Entity) {}
}
impl EntityMapper for (Entity, Entity) {
#[inline]
fn get_mapped(&mut self, source: Entity) -> Entity {
if source == self.0 {
self.1
} else {
source
}
}
fn set_mapped(&mut self, _source: Entity, _target: Entity) {}
}
impl EntityMapper for &mut dyn EntityMapper {
fn get_mapped(&mut self, source: Entity) -> Entity {
(*self).get_mapped(source)
}
fn set_mapped(&mut self, source: Entity, target: Entity) {
(*self).set_mapped(source, target);
}
}
impl EntityMapper for SceneEntityMapper<'_> {
fn get_mapped(&mut self, source: Entity) -> Entity {
if let Some(&mapped) = self.map.get(&source) {
return mapped;
}
let new = Entity::from_index_and_generation(
self.dead_start.index(),
self.dead_start.generation.after_versions(self.generations),
);
self.generations = self.generations.wrapping_add(1);
self.map.insert(source, new);
new
}
fn set_mapped(&mut self, source: Entity, target: Entity) {
self.map.insert(source, target);
}
}
impl EntityMapper for EntityHashMap<Entity> {
fn get_mapped(&mut self, source: Entity) -> Entity {
self.get(&source).cloned().unwrap_or(source)
}
fn set_mapped(&mut self, source: Entity, target: Entity) {
self.insert(source, target);
}
}
pub struct SceneEntityMapper<'m> {
map: &'m mut EntityHashMap<Entity>,
dead_start: Entity,
generations: u32,
}
impl<'m> SceneEntityMapper<'m> {
pub fn get_map(&'m self) -> &'m EntityHashMap<Entity> {
self.map
}
pub fn get_map_mut(&'m mut self) -> &'m mut EntityHashMap<Entity> {
self.map
}
pub fn new(map: &'m mut EntityHashMap<Entity>, world: &World) -> Self {
Self {
map,
dead_start: world.allocator.alloc(),
generations: 0,
}
}
pub fn finish(self, world: &mut World) {
let reuse_row = unsafe {
world
.entities
.mark_free(self.dead_start.index(), self.generations)
};
world.allocator.free(reuse_row);
}
pub fn world_scope<R>(
entity_map: &'m mut EntityHashMap<Entity>,
world: &mut World,
f: impl FnOnce(&mut World, &mut Self) -> R,
) -> R {
let mut mapper = Self::new(entity_map, world);
let result = f(world, &mut mapper);
mapper.finish(world);
result
}
}
#[cfg(test)]
mod tests {
use crate::{
entity::{Entity, EntityHashMap, EntityMapper, SceneEntityMapper},
world::World,
};
#[test]
fn entity_mapper() {
let mut map = EntityHashMap::default();
let mut world = World::new();
let mut mapper = SceneEntityMapper::new(&mut map, &world);
let mapped_ent = Entity::from_raw_u32(1).unwrap();
let dead_ref = mapper.get_mapped(mapped_ent);
assert_eq!(
dead_ref,
mapper.get_mapped(mapped_ent),
"should persist the allocated mapping from the previous line"
);
assert_eq!(
mapper.get_mapped(Entity::from_raw_u32(2).unwrap()).index(),
dead_ref.index(),
"should re-use the same index for further dead refs"
);
mapper.finish(&mut world);
let entity = world.spawn_empty().id();
assert_eq!(entity.index(), dead_ref.index());
assert!(entity
.generation()
.cmp_approx(&dead_ref.generation())
.is_gt());
}
#[test]
fn world_scope_reserves_generations() {
let mut map = EntityHashMap::default();
let mut world = World::new();
let dead_ref = SceneEntityMapper::world_scope(&mut map, &mut world, |_, mapper| {
mapper.get_mapped(Entity::from_raw_u32(0).unwrap())
});
let entity = world.spawn_empty().id();
assert_eq!(entity.index(), dead_ref.index());
assert!(entity
.generation()
.cmp_approx(&dead_ref.generation())
.is_gt());
}
}