1- pub use bevy_ecs_macros:: VisitEntities ;
1+ pub use bevy_ecs_macros:: { VisitEntities , VisitEntitiesMut } ;
22
33use crate :: entity:: Entity ;
44
@@ -28,14 +28,44 @@ impl VisitEntities for Entity {
2828 }
2929}
3030
31+ /// Apply an operation to mutable references to all entities in a container.
32+ ///
33+ /// This is implemented by default for types that implement [`IntoIterator`].
34+ ///
35+ /// It may be useful to implement directly for types that can't produce an
36+ /// iterator for lifetime reasons, such as those involving internal mutexes.
37+ pub trait VisitEntitiesMut : VisitEntities {
38+ /// Apply an operation to mutable references to all contained entities.
39+ fn visit_entities_mut < F : FnMut ( & mut Entity ) > ( & mut self , f : F ) ;
40+ }
41+
42+ impl < T : VisitEntities > VisitEntitiesMut for T
43+ where
44+ for < ' a > & ' a mut T : IntoIterator < Item = & ' a mut Entity > ,
45+ {
46+ fn visit_entities_mut < F : FnMut ( & mut Entity ) > ( & mut self , f : F ) {
47+ self . into_iter ( ) . for_each ( f) ;
48+ }
49+ }
50+
51+ impl VisitEntitiesMut for Entity {
52+ fn visit_entities_mut < F : FnMut ( & mut Entity ) > ( & mut self , mut f : F ) {
53+ f ( self ) ;
54+ }
55+ }
56+
3157#[ cfg( test) ]
3258mod tests {
33- use crate :: { self as bevy_ecs, entity:: Entities } ;
59+ use crate :: {
60+ self as bevy_ecs,
61+ entity:: { Entities , EntityHashMap , MapEntities , SceneEntityMapper } ,
62+ world:: World ,
63+ } ;
3464 use bevy_utils:: HashSet ;
3565
3666 use super :: * ;
3767
38- #[ derive( VisitEntities ) ]
68+ #[ derive( VisitEntities , Debug , PartialEq ) ]
3969 struct Foo {
4070 ordered : Vec < Entity > ,
4171 unordered : HashSet < Entity > ,
@@ -45,10 +75,29 @@ mod tests {
4575 not_an_entity : String ,
4676 }
4777
78+ // Need a manual impl since VisitEntitiesMut isn't implemented for `HashSet`.
79+ // We don't expect users to actually do this - it's only for test purposes
80+ // to prove out the automatic `MapEntites` impl we get with `VisitEntitiesMut`.
81+ impl VisitEntitiesMut for Foo {
82+ fn visit_entities_mut < F : FnMut ( & mut Entity ) > ( & mut self , mut f : F ) {
83+ self . ordered . visit_entities_mut ( & mut f) ;
84+ self . unordered = self
85+ . unordered
86+ . drain ( )
87+ . map ( |mut entity| {
88+ f ( & mut entity) ;
89+ entity
90+ } )
91+ . collect ( ) ;
92+ f ( & mut self . single )
93+ }
94+ }
95+
4896 #[ test]
4997 fn visit_entities ( ) {
50- let entities = Entities :: new ( ) ;
51- let foo = Foo {
98+ let mut world = World :: new ( ) ;
99+ let entities = world. entities ( ) ;
100+ let mut foo = Foo {
52101 ordered : vec ! [ entities. reserve_entity( ) , entities. reserve_entity( ) ] ,
53102 unordered : [
54103 entities. reserve_entity ( ) ,
@@ -61,21 +110,41 @@ mod tests {
61110 not_an_entity : "Bar" . into ( ) ,
62111 } ;
63112
113+ let mut entity_map = EntityHashMap :: < Entity > :: default ( ) ;
114+ let mut remapped = Foo {
115+ ordered : vec ! [ ] ,
116+ unordered : HashSet :: new ( ) ,
117+ single : Entity :: PLACEHOLDER ,
118+ not_an_entity : foo. not_an_entity . clone ( ) ,
119+ } ;
120+
64121 // Note: this assumes that the VisitEntities derive is field-ordered,
65122 // which isn't explicitly stated/guaranteed.
66123 // If that changes, this test will fail, but that might be OK if
67124 // we're intentionally breaking that assumption.
68125 let mut i = 0 ;
69126 foo. visit_entities ( |entity| {
127+ let new_entity = entities. reserve_entity ( ) ;
70128 if i < foo. ordered . len ( ) {
71129 assert_eq ! ( entity, foo. ordered[ i] ) ;
130+ remapped. ordered . push ( new_entity) ;
72131 } else if i < foo. ordered . len ( ) + foo. unordered . len ( ) {
73132 assert ! ( foo. unordered. contains( & entity) ) ;
133+ remapped. unordered . insert ( new_entity) ;
74134 } else {
75135 assert_eq ! ( entity, foo. single) ;
136+ remapped. single = new_entity;
76137 }
77138
139+ entity_map. insert ( entity, new_entity) ;
140+
78141 i += 1 ;
79142 } ) ;
143+
144+ SceneEntityMapper :: world_scope ( & mut entity_map, & mut world, |_, mapper| {
145+ foo. map_entities ( mapper) ;
146+ } ) ;
147+
148+ assert_eq ! ( foo, remapped) ;
80149 }
81150}
0 commit comments