1- use  crate :: entity:: Entity ; 
1+ use  crate :: { entity:: Entity ,  world :: World } ; 
22use  bevy_utils:: { Entry ,  HashMap } ; 
3- use  std:: fmt; 
4- 
5- /// The errors that might be returned while using [`MapEntities::map_entities`]. 
6- #[ derive( Debug ) ]  
7- pub  enum  MapEntitiesError  { 
8-     EntityNotFound ( Entity ) , 
9- } 
10- 
11- impl  std:: error:: Error  for  MapEntitiesError  { } 
12- 
13- impl  fmt:: Display  for  MapEntitiesError  { 
14-     fn  fmt ( & self ,  f :  & mut  fmt:: Formatter )  -> fmt:: Result  { 
15-         match  self  { 
16-             MapEntitiesError :: EntityNotFound ( _)  => { 
17-                 write ! ( f,  "the given entity does not exist in the map" ) 
18-             } 
19-         } 
20-     } 
21- } 
223
234/// Operation to map all contained [`Entity`] fields in a type to new values. 
245/// 
@@ -33,7 +14,7 @@ impl fmt::Display for MapEntitiesError {
3314/// 
3415/// ```rust 
3516/// use bevy_ecs::prelude::*; 
36- /// use bevy_ecs::entity::{EntityMap , MapEntities, MapEntitiesError }; 
17+ /// use bevy_ecs::entity::{EntityMapper , MapEntities}; 
3718/// 
3819/// #[derive(Component)] 
3920/// struct Spring { 
@@ -42,10 +23,9 @@ impl fmt::Display for MapEntitiesError {
4223/// } 
4324/// 
4425/// impl MapEntities for Spring { 
45- ///     fn map_entities(&mut self, entity_map: &EntityMap) -> Result<(), MapEntitiesError> { 
46- ///         self.a = entity_map.get(self.a)?; 
47- ///         self.b = entity_map.get(self.b)?; 
48- ///         Ok(()) 
26+ ///     fn map_entities(&mut self, entity_mapper: &mut EntityMapper) { 
27+ ///         self.a = entity_mapper.get_or_reserve(self.a); 
28+ ///         self.b = entity_mapper.get_or_reserve(self.b); 
4929///     } 
5030/// } 
5131/// ``` 
@@ -55,16 +35,22 @@ pub trait MapEntities {
5535    /// Updates all [`Entity`] references stored inside using `entity_map`. 
5636     /// 
5737     /// Implementors should look up any and all [`Entity`] values stored within and 
58-      /// update them to the mapped values via `entity_map `. 
59-      fn  map_entities ( & mut  self ,  entity_map :  & EntityMap )  ->  Result < ( ) ,   MapEntitiesError > ; 
38+      /// update them to the mapped values via `entity_mapper `. 
39+      fn  map_entities ( & mut  self ,  entity_mapper :  & mut   EntityMapper ) ; 
6040} 
6141
6242/// A mapping from one set of entities to another. 
6343/// 
6444/// The API generally follows [`HashMap`], but each [`Entity`] is returned by value, as they are [`Copy`]. 
6545/// 
66- /// This is typically used to coordinate data transfer between sets of entities, such as between a scene and the world or over the network. 
67- /// This is required as [`Entity`] identifiers are opaque; you cannot and do not want to reuse identifiers directly. 
46+ /// This is typically used to coordinate data transfer between sets of entities, such as between a scene and the world 
47+ /// or over the network. This is required as [`Entity`] identifiers are opaque; you cannot and do not want to reuse 
48+ /// identifiers directly. 
49+ /// 
50+ /// On its own, an `EntityMap` is not capable of allocating new entity identifiers, which is needed to map references 
51+ /// to entities that lie outside the source entity set. To do this, an `EntityMap` can be wrapped in an 
52+ /// [`EntityMapper`] which scopes it to a particular destination [`World`] and allows new identifiers to be allocated. 
53+ /// This functionality can be accessed through [`Self::world_scope()`]. 
6854#[ derive( Default ,  Debug ) ]  
6955pub  struct  EntityMap  { 
7056    map :  HashMap < Entity ,  Entity > , 
@@ -91,11 +77,8 @@ impl EntityMap {
9177    } 
9278
9379    /// Returns the corresponding mapped entity. 
94-      pub  fn  get ( & self ,  entity :  Entity )  -> Result < Entity ,  MapEntitiesError >  { 
95-         self . map 
96-             . get ( & entity) 
97-             . cloned ( ) 
98-             . ok_or ( MapEntitiesError :: EntityNotFound ( entity) ) 
80+      pub  fn  get ( & self ,  entity :  Entity )  -> Option < Entity >  { 
81+         self . map . get ( & entity) . copied ( ) 
9982    } 
10083
10184    /// An iterator visiting all keys in arbitrary order. 
@@ -122,4 +105,138 @@ impl EntityMap {
122105     pub  fn  iter ( & self )  -> impl  Iterator < Item  = ( Entity ,  Entity ) >  + ' _  { 
123106        self . map . iter ( ) . map ( |( from,  to) | ( * from,  * to) ) 
124107    } 
108+ 
109+     /// Creates an [`EntityMapper`] from this [`EntityMap`] and scoped to the provided [`World`], then calls the 
110+      /// provided function with it. This allows one to allocate new entity references in the provided `World` that are 
111+      /// guaranteed to never point at a living entity now or in the future. This functionality is useful for safely 
112+      /// mapping entity identifiers that point at entities outside the source world. The passed function, `f`, is called 
113+      /// within the scope of the passed world. Its return value is then returned from `world_scope` as the generic type 
114+      /// parameter `R`. 
115+      pub  fn  world_scope < R > ( 
116+         & mut  self , 
117+         world :  & mut  World , 
118+         f :  impl  FnOnce ( & mut  World ,  & mut  EntityMapper )  -> R , 
119+     )  -> R  { 
120+         let  mut  mapper = EntityMapper :: new ( self ,  world) ; 
121+         let  result = f ( world,  & mut  mapper) ; 
122+         mapper. finish ( world) ; 
123+         result
124+     } 
125+ } 
126+ 
127+ /// A wrapper for [`EntityMap`], augmenting it with the ability to allocate new [`Entity`] references in a destination 
128+ /// world. These newly allocated references are guaranteed to never point to any living entity in that world. 
129+ /// 
130+ /// References are allocated by returning increasing generations starting from an internally initialized base 
131+ /// [`Entity`]. After it is finished being used by [`MapEntities`] implementations, this entity is despawned and the 
132+ /// requisite number of generations reserved. 
133+ pub  struct  EntityMapper < ' m >  { 
134+     /// The wrapped [`EntityMap`]. 
135+      map :  & ' m  mut  EntityMap , 
136+     /// A base [`Entity`] used to allocate new references. 
137+      dead_start :  Entity , 
138+     /// The number of generations this mapper has allocated thus far. 
139+      generations :  u32 , 
140+ } 
141+ 
142+ impl < ' m >  EntityMapper < ' m >  { 
143+     /// Returns the corresponding mapped entity or reserves a new dead entity ID if it is absent. 
144+      pub  fn  get_or_reserve ( & mut  self ,  entity :  Entity )  -> Entity  { 
145+         if  let  Some ( mapped)  = self . map . get ( entity)  { 
146+             return  mapped; 
147+         } 
148+ 
149+         // this new entity reference is specifically designed to never represent any living entity 
150+         let  new = Entity  { 
151+             generation :  self . dead_start . generation  + self . generations , 
152+             index :  self . dead_start . index , 
153+         } ; 
154+         self . generations  += 1 ; 
155+ 
156+         self . map . insert ( entity,  new) ; 
157+ 
158+         new
159+     } 
160+ 
161+     /// Gets a reference to the underlying [`EntityMap`]. 
162+      pub  fn  get_map ( & ' m  self )  -> & ' m  EntityMap  { 
163+         self . map 
164+     } 
165+ 
166+     /// Gets a mutable reference to the underlying [`EntityMap`] 
167+      pub  fn  get_map_mut ( & ' m  mut  self )  -> & ' m  mut  EntityMap  { 
168+         self . map 
169+     } 
170+ 
171+     /// Creates a new [`EntityMapper`], spawning a temporary base [`Entity`] in the provided [`World`] 
172+      fn  new ( map :  & ' m  mut  EntityMap ,  world :  & mut  World )  -> Self  { 
173+         Self  { 
174+             map, 
175+             // SAFETY: Entities data is kept in a valid state via `EntityMap::world_scope` 
176+             dead_start :  unsafe  {  world. entities_mut ( ) . alloc ( )  } , 
177+             generations :  0 , 
178+         } 
179+     } 
180+ 
181+     /// Reserves the allocated references to dead entities within the world. This frees the temporary base 
182+      /// [`Entity`] while reserving extra generations via [`crate::entity::Entities::reserve_generations`]. Because this 
183+      /// renders the [`EntityMapper`] unable to safely allocate any more references, this method takes ownership of 
184+      /// `self` in order to render it unusable. 
185+      fn  finish ( self ,  world :  & mut  World )  { 
186+         // SAFETY: Entities data is kept in a valid state via `EntityMap::world_scope` 
187+         let  entities = unsafe  {  world. entities_mut ( )  } ; 
188+         assert ! ( entities. free( self . dead_start) . is_some( ) ) ; 
189+         assert ! ( entities. reserve_generations( self . dead_start. index,  self . generations) ) ; 
190+     } 
191+ } 
192+ 
193+ #[ cfg( test) ]  
194+ mod  tests { 
195+     use  super :: { EntityMap ,  EntityMapper } ; 
196+     use  crate :: { entity:: Entity ,  world:: World } ; 
197+ 
198+     #[ test]  
199+     fn  entity_mapper ( )  { 
200+         const  FIRST_IDX :  u32  = 1 ; 
201+         const  SECOND_IDX :  u32  = 2 ; 
202+ 
203+         let  mut  map = EntityMap :: default ( ) ; 
204+         let  mut  world = World :: new ( ) ; 
205+         let  mut  mapper = EntityMapper :: new ( & mut  map,  & mut  world) ; 
206+ 
207+         let  mapped_ent = Entity :: new ( FIRST_IDX ,  0 ) ; 
208+         let  dead_ref = mapper. get_or_reserve ( mapped_ent) ; 
209+ 
210+         assert_eq ! ( 
211+             dead_ref, 
212+             mapper. get_or_reserve( mapped_ent) , 
213+             "should persist the allocated mapping from the previous line" 
214+         ) ; 
215+         assert_eq ! ( 
216+             mapper. get_or_reserve( Entity :: new( SECOND_IDX ,  0 ) ) . index( ) , 
217+             dead_ref. index( ) , 
218+             "should re-use the same index for further dead refs" 
219+         ) ; 
220+ 
221+         mapper. finish ( & mut  world) ; 
222+         // Next allocated entity should be a further generation on the same index 
223+         let  entity = world. spawn_empty ( ) . id ( ) ; 
224+         assert_eq ! ( entity. index( ) ,  dead_ref. index( ) ) ; 
225+         assert ! ( entity. generation( )  > dead_ref. generation( ) ) ; 
226+     } 
227+ 
228+     #[ test]  
229+     fn  world_scope_reserves_generations ( )  { 
230+         let  mut  map = EntityMap :: default ( ) ; 
231+         let  mut  world = World :: new ( ) ; 
232+ 
233+         let  dead_ref = map. world_scope ( & mut  world,  |_,  mapper| { 
234+             mapper. get_or_reserve ( Entity :: new ( 0 ,  0 ) ) 
235+         } ) ; 
236+ 
237+         // Next allocated entity should be a further generation on the same index 
238+         let  entity = world. spawn_empty ( ) . id ( ) ; 
239+         assert_eq ! ( entity. index( ) ,  dead_ref. index( ) ) ; 
240+         assert ! ( entity. generation( )  > dead_ref. generation( ) ) ; 
241+     } 
125242} 
0 commit comments