Skip to content

Commit 04ceb46

Browse files
authored
Use EntityHashMap for EntityMapper (#10415)
# Objective - There is a specialized hasher for entities: [`EntityHashMap`](https://docs.rs/bevy/latest/bevy/utils/type.EntityHashMap.html) - [`EntityMapper`] currently uses a normal `HashMap<Entity, Entity>` - Fixes #10391 ## Solution - Replace the normal `HashMap` with the more performant `EntityHashMap` ## Questions - This does change public API. Should a system be implemented to help migrate code? - Perhaps an `impl From<HashMap<K, V, S>> for EntityHashMap<K, V>` - I updated to docs for each function that I changed, but I may have missed something --- ## Changelog - Changed `EntityMapper` to use `EntityHashMap` instead of normal `HashMap` ## Migration Guide If you are using the following types, update their listed methods to use the new `EntityHashMap`. `EntityHashMap` has the same methods as the normal `HashMap`, so you just need to replace the name. ### `EntityMapper` - `get_map` - `get_mut_map` - `new` - `world_scope` ### `ReflectMapEntities` - `map_all_entities` - `map_entities` - `write_to_world` ### `InstanceInfo` - `entity_map` - This is a property, not a method. --- This is my first time contributing in a while, and I'm not familiar with the usage of `EntityMapper`. I changed the type definition and fixed all errors, but there may have been things I've missed. Please keep an eye out for me!
1 parent 6ce33d0 commit 04ceb46

File tree

6 files changed

+43
-39
lines changed

6 files changed

+43
-39
lines changed

crates/bevy_ecs/src/entity/map_entities.rs

Lines changed: 15 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,11 @@
11
use crate::{entity::Entity, world::World};
2-
use bevy_utils::HashMap;
2+
use bevy_utils::EntityHashMap;
33

44
/// Operation to map all contained [`Entity`] fields in a type to new values.
55
///
66
/// As entity IDs are valid only for the [`World`] they're sourced from, using [`Entity`]
77
/// as references in components copied from another world will be invalid. This trait
8-
/// allows defining custom mappings for these references via [`HashMap<Entity, Entity>`]
8+
/// allows defining custom mappings for these references via [`EntityHashMap<Entity, Entity>`]
99
///
1010
/// Implementing this trait correctly is required for properly loading components
1111
/// with entity references from scenes.
@@ -39,7 +39,7 @@ pub trait MapEntities {
3939
fn map_entities(&mut self, entity_mapper: &mut EntityMapper);
4040
}
4141

42-
/// A wrapper for [`HashMap<Entity, Entity>`], augmenting it with the ability to allocate new [`Entity`] references in a destination
42+
/// A wrapper for [`EntityHashMap<Entity, Entity>`], augmenting it with the ability to allocate new [`Entity`] references in a destination
4343
/// world. These newly allocated references are guaranteed to never point to any living entity in that world.
4444
///
4545
/// References are allocated by returning increasing generations starting from an internally initialized base
@@ -52,9 +52,9 @@ pub struct EntityMapper<'m> {
5252
/// or over the network. This is required as [`Entity`] identifiers are opaque; you cannot and do not want to reuse
5353
/// identifiers directly.
5454
///
55-
/// On its own, a [`HashMap<Entity, Entity>`] is not capable of allocating new entity identifiers, which is needed to map references
55+
/// On its own, a [`EntityHashMap<Entity, Entity>`] is not capable of allocating new entity identifiers, which is needed to map references
5656
/// to entities that lie outside the source entity set. This functionality can be accessed through [`EntityMapper::world_scope()`].
57-
map: &'m mut HashMap<Entity, Entity>,
57+
map: &'m mut EntityHashMap<Entity, Entity>,
5858
/// A base [`Entity`] used to allocate new references.
5959
dead_start: Entity,
6060
/// The number of generations this mapper has allocated thus far.
@@ -80,18 +80,18 @@ impl<'m> EntityMapper<'m> {
8080
new
8181
}
8282

83-
/// Gets a reference to the underlying [`HashMap<Entity, Entity>`].
84-
pub fn get_map(&'m self) -> &'m HashMap<Entity, Entity> {
83+
/// Gets a reference to the underlying [`EntityHashMap<Entity, Entity>`].
84+
pub fn get_map(&'m self) -> &'m EntityHashMap<Entity, Entity> {
8585
self.map
8686
}
8787

88-
/// Gets a mutable reference to the underlying [`HashMap<Entity, Entity>`].
89-
pub fn get_map_mut(&'m mut self) -> &'m mut HashMap<Entity, Entity> {
88+
/// Gets a mutable reference to the underlying [`EntityHashMap<Entity, Entity>`].
89+
pub fn get_map_mut(&'m mut self) -> &'m mut EntityHashMap<Entity, Entity> {
9090
self.map
9191
}
9292

9393
/// Creates a new [`EntityMapper`], spawning a temporary base [`Entity`] in the provided [`World`]
94-
fn new(map: &'m mut HashMap<Entity, Entity>, world: &mut World) -> Self {
94+
fn new(map: &'m mut EntityHashMap<Entity, Entity>, world: &mut World) -> Self {
9595
Self {
9696
map,
9797
// SAFETY: Entities data is kept in a valid state via `EntityMapper::world_scope`
@@ -111,14 +111,14 @@ impl<'m> EntityMapper<'m> {
111111
assert!(entities.reserve_generations(self.dead_start.index, self.generations));
112112
}
113113

114-
/// Creates an [`EntityMapper`] from a provided [`World`] and [`HashMap<Entity, Entity>`], then calls the
114+
/// Creates an [`EntityMapper`] from a provided [`World`] and [`EntityHashMap<Entity, Entity>`], then calls the
115115
/// provided function with it. This allows one to allocate new entity references in this [`World`] that are
116116
/// guaranteed to never point at a living entity now or in the future. This functionality is useful for safely
117117
/// mapping entity identifiers that point at entities outside the source world. The passed function, `f`, is called
118118
/// within the scope of this world. Its return value is then returned from `world_scope` as the generic type
119119
/// parameter `R`.
120120
pub fn world_scope<R>(
121-
entity_map: &'m mut HashMap<Entity, Entity>,
121+
entity_map: &'m mut EntityHashMap<Entity, Entity>,
122122
world: &mut World,
123123
f: impl FnOnce(&mut World, &mut Self) -> R,
124124
) -> R {
@@ -131,7 +131,7 @@ impl<'m> EntityMapper<'m> {
131131

132132
#[cfg(test)]
133133
mod tests {
134-
use bevy_utils::HashMap;
134+
use bevy_utils::EntityHashMap;
135135

136136
use crate::{
137137
entity::{Entity, EntityMapper},
@@ -143,7 +143,7 @@ mod tests {
143143
const FIRST_IDX: u32 = 1;
144144
const SECOND_IDX: u32 = 2;
145145

146-
let mut map = HashMap::default();
146+
let mut map = EntityHashMap::default();
147147
let mut world = World::new();
148148
let mut mapper = EntityMapper::new(&mut map, &mut world);
149149

@@ -170,7 +170,7 @@ mod tests {
170170

171171
#[test]
172172
fn world_scope_reserves_generations() {
173-
let mut map = HashMap::default();
173+
let mut map = EntityHashMap::default();
174174
let mut world = World::new();
175175

176176
let dead_ref = EntityMapper::world_scope(&mut map, &mut world, |_, mapper| {

crates/bevy_ecs/src/reflect/map_entities.rs

Lines changed: 12 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ use crate::{
44
world::World,
55
};
66
use bevy_reflect::FromType;
7-
use bevy_utils::HashMap;
7+
use bevy_utils::EntityHashMap;
88

99
/// For a specific type of component, this maps any fields with values of type [`Entity`] to a new world.
1010
/// Since a given `Entity` ID is only valid for the world it came from, when performing deserialization
@@ -18,29 +18,33 @@ pub struct ReflectMapEntities {
1818
}
1919

2020
impl ReflectMapEntities {
21-
/// A general method for applying [`MapEntities`] behavior to all elements in an [`HashMap<Entity, Entity>`].
21+
/// A general method for applying [`MapEntities`] behavior to all elements in an [`EntityHashMap<Entity, Entity>`].
2222
///
23-
/// Be mindful in its usage: Works best in situations where the entities in the [`HashMap<Entity, Entity>`] are newly
23+
/// Be mindful in its usage: Works best in situations where the entities in the [`EntityHashMap<Entity, Entity>`] are newly
2424
/// created, before systems have a chance to add new components. If some of the entities referred to
25-
/// by the [`HashMap<Entity, Entity>`] might already contain valid entity references, you should use [`map_entities`](Self::map_entities).
25+
/// by the [`EntityHashMap<Entity, Entity>`] might already contain valid entity references, you should use [`map_entities`](Self::map_entities).
2626
///
2727
/// An example of this: A scene can be loaded with `Parent` components, but then a `Parent` component can be added
2828
/// to these entities after they have been loaded. If you reload the scene using [`map_all_entities`](Self::map_all_entities), those `Parent`
2929
/// components with already valid entity references could be updated to point at something else entirely.
30-
pub fn map_all_entities(&self, world: &mut World, entity_map: &mut HashMap<Entity, Entity>) {
30+
pub fn map_all_entities(
31+
&self,
32+
world: &mut World,
33+
entity_map: &mut EntityHashMap<Entity, Entity>,
34+
) {
3135
EntityMapper::world_scope(entity_map, world, self.map_all_entities);
3236
}
3337

34-
/// A general method for applying [`MapEntities`] behavior to elements in an [`HashMap<Entity, Entity>`]. Unlike
38+
/// A general method for applying [`MapEntities`] behavior to elements in an [`EntityHashMap<Entity, Entity>`]. Unlike
3539
/// [`map_all_entities`](Self::map_all_entities), this is applied to specific entities, not all values
36-
/// in the [`HashMap<Entity, Entity>`].
40+
/// in the [`EntityHashMap<Entity, Entity>`].
3741
///
3842
/// This is useful mostly for when you need to be careful not to update components that already contain valid entity
3943
/// values. See [`map_all_entities`](Self::map_all_entities) for more details.
4044
pub fn map_entities(
4145
&self,
4246
world: &mut World,
43-
entity_map: &mut HashMap<Entity, Entity>,
47+
entity_map: &mut EntityHashMap<Entity, Entity>,
4448
entities: &[Entity],
4549
) {
4650
EntityMapper::world_scope(entity_map, world, |world, mapper| {

crates/bevy_scene/src/dynamic_scene.rs

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ use bevy_ecs::{
55
world::World,
66
};
77
use bevy_reflect::{Reflect, TypePath, TypeRegistryArc};
8-
use bevy_utils::HashMap;
8+
use bevy_utils::{EntityHashMap, HashMap};
99
use std::any::TypeId;
1010

1111
#[cfg(feature = "serialize")]
@@ -65,7 +65,7 @@ impl DynamicScene {
6565
pub fn write_to_world_with(
6666
&self,
6767
world: &mut World,
68-
entity_map: &mut HashMap<Entity, Entity>,
68+
entity_map: &mut EntityHashMap<Entity, Entity>,
6969
type_registry: &AppTypeRegistry,
7070
) -> Result<(), SceneSpawnError> {
7171
let type_registry = type_registry.read();
@@ -163,7 +163,7 @@ impl DynamicScene {
163163
pub fn write_to_world(
164164
&self,
165165
world: &mut World,
166-
entity_map: &mut HashMap<Entity, Entity>,
166+
entity_map: &mut EntityHashMap<Entity, Entity>,
167167
) -> Result<(), SceneSpawnError> {
168168
let registry = world.resource::<AppTypeRegistry>().clone();
169169
self.write_to_world_with(world, entity_map, &registry)
@@ -193,7 +193,7 @@ where
193193
mod tests {
194194
use bevy_ecs::{reflect::AppTypeRegistry, system::Command, world::World};
195195
use bevy_hierarchy::{AddChild, Parent};
196-
use bevy_utils::HashMap;
196+
use bevy_utils::EntityHashMap;
197197

198198
use crate::dynamic_scene_builder::DynamicSceneBuilder;
199199

@@ -222,7 +222,7 @@ mod tests {
222222
.extract_entity(original_parent_entity)
223223
.extract_entity(original_child_entity)
224224
.build();
225-
let mut entity_map = HashMap::default();
225+
let mut entity_map = EntityHashMap::default();
226226
scene.write_to_world(&mut world, &mut entity_map).unwrap();
227227

228228
let &from_scene_parent_entity = entity_map.get(&original_parent_entity).unwrap();

crates/bevy_scene/src/scene.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ use bevy_ecs::{
55
world::World,
66
};
77
use bevy_reflect::TypePath;
8-
use bevy_utils::HashMap;
8+
use bevy_utils::EntityHashMap;
99

1010
/// To spawn a scene, you can use either:
1111
/// * [`SceneSpawner::spawn`](crate::SceneSpawner::spawn)
@@ -31,7 +31,7 @@ impl Scene {
3131
type_registry: &AppTypeRegistry,
3232
) -> Result<Scene, SceneSpawnError> {
3333
let mut world = World::new();
34-
let mut entity_map = HashMap::default();
34+
let mut entity_map = EntityHashMap::default();
3535
dynamic_scene.write_to_world_with(&mut world, &mut entity_map, type_registry)?;
3636

3737
Ok(Self { world })
@@ -57,7 +57,7 @@ impl Scene {
5757
type_registry: &AppTypeRegistry,
5858
) -> Result<InstanceInfo, SceneSpawnError> {
5959
let mut instance_info = InstanceInfo {
60-
entity_map: HashMap::default(),
60+
entity_map: EntityHashMap::default(),
6161
};
6262

6363
let type_registry = type_registry.read();

crates/bevy_scene/src/scene_spawner.rs

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ use bevy_ecs::{
88
world::{Mut, World},
99
};
1010
use bevy_hierarchy::{AddChild, Parent};
11-
use bevy_utils::{tracing::error, HashMap, HashSet};
11+
use bevy_utils::{tracing::error, EntityHashMap, HashMap, HashSet};
1212
use thiserror::Error;
1313
use uuid::Uuid;
1414

@@ -25,7 +25,7 @@ pub struct SceneInstanceReady {
2525
#[derive(Debug)]
2626
pub struct InstanceInfo {
2727
/// Mapping of entities from the scene world to the instance world.
28-
pub entity_map: HashMap<Entity, Entity>,
28+
pub entity_map: EntityHashMap<Entity, Entity>,
2929
}
3030

3131
/// Unique id identifying a scene instance.
@@ -199,7 +199,7 @@ impl SceneSpawner {
199199
world: &mut World,
200200
id: impl Into<AssetId<DynamicScene>>,
201201
) -> Result<(), SceneSpawnError> {
202-
let mut entity_map = HashMap::default();
202+
let mut entity_map = EntityHashMap::default();
203203
let id = id.into();
204204
Self::spawn_dynamic_internal(world, id, &mut entity_map)?;
205205
let instance_id = InstanceId::new();
@@ -213,7 +213,7 @@ impl SceneSpawner {
213213
fn spawn_dynamic_internal(
214214
world: &mut World,
215215
id: AssetId<DynamicScene>,
216-
entity_map: &mut HashMap<Entity, Entity>,
216+
entity_map: &mut EntityHashMap<Entity, Entity>,
217217
) -> Result<(), SceneSpawnError> {
218218
world.resource_scope(|world, scenes: Mut<Assets<DynamicScene>>| {
219219
let scene = scenes
@@ -297,7 +297,7 @@ impl SceneSpawner {
297297
let scenes_to_spawn = std::mem::take(&mut self.dynamic_scenes_to_spawn);
298298

299299
for (id, instance_id) in scenes_to_spawn {
300-
let mut entity_map = HashMap::default();
300+
let mut entity_map = EntityHashMap::default();
301301

302302
match Self::spawn_dynamic_internal(world, id, &mut entity_map) {
303303
Ok(_) => {

crates/bevy_scene/src/serde.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -504,7 +504,7 @@ mod tests {
504504
use bevy_ecs::reflect::{AppTypeRegistry, ReflectMapEntities};
505505
use bevy_ecs::world::FromWorld;
506506
use bevy_reflect::{Reflect, ReflectSerialize};
507-
use bevy_utils::HashMap;
507+
use bevy_utils::EntityHashMap;
508508
use bincode::Options;
509509
use serde::de::DeserializeSeed;
510510
use serde::Serialize;
@@ -678,7 +678,7 @@ mod tests {
678678
"expected `entities` to contain 3 entities"
679679
);
680680

681-
let mut map = HashMap::default();
681+
let mut map = EntityHashMap::default();
682682
let mut dst_world = create_world();
683683
scene.write_to_world(&mut dst_world, &mut map).unwrap();
684684

@@ -717,7 +717,7 @@ mod tests {
717717

718718
let deserialized_scene = scene_deserializer.deserialize(&mut deserializer).unwrap();
719719

720-
let mut map = HashMap::default();
720+
let mut map = EntityHashMap::default();
721721
let mut dst_world = create_world();
722722
deserialized_scene
723723
.write_to_world(&mut dst_world, &mut map)

0 commit comments

Comments
 (0)