Skip to content

Commit 73d774e

Browse files
committed
bring back VisitEntitiesMut
1 parent d8dde38 commit 73d774e

File tree

11 files changed

+198
-64
lines changed

11 files changed

+198
-64
lines changed

crates/bevy_animation/src/lib.rs

Lines changed: 4 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -28,9 +28,9 @@ use bevy_app::{App, Plugin, PostUpdate};
2828
use bevy_asset::{Asset, AssetApp, Assets, Handle};
2929
use bevy_core::Name;
3030
use bevy_ecs::{
31-
entity::{MapEntities, VisitEntities},
31+
entity::{VisitEntities, VisitEntitiesMut},
3232
prelude::*,
33-
reflect::{ReflectMapEntities, ReflectVisitEntities},
33+
reflect::{ReflectMapEntities, ReflectVisitEntities, ReflectVisitEntitiesMut},
3434
world::EntityMutExcept,
3535
};
3636
use bevy_math::FloatExt;
@@ -530,8 +530,8 @@ impl Hash for AnimationTargetId {
530530
/// Note that each entity can only be animated by one animation player at a
531531
/// time. However, you can change [`AnimationTarget`]'s `player` property at
532532
/// runtime to change which player is responsible for animating the entity.
533-
#[derive(Clone, Copy, Component, Reflect, VisitEntities)]
534-
#[reflect(Component, MapEntities, VisitEntities)]
533+
#[derive(Clone, Copy, Component, Reflect, VisitEntities, VisitEntitiesMut)]
534+
#[reflect(Component, MapEntities, VisitEntities, VisitEntitiesMut)]
535535
pub struct AnimationTarget {
536536
/// The ID of this animation target.
537537
///
@@ -1302,12 +1302,6 @@ impl From<&Name> for AnimationTargetId {
13021302
}
13031303
}
13041304

1305-
impl MapEntities for AnimationTarget {
1306-
fn map_entities<M: EntityMapper>(&mut self, entity_mapper: &mut M) {
1307-
self.player = entity_mapper.map_entity(self.player);
1308-
}
1309-
}
1310-
13111305
impl AnimationGraphEvaluator {
13121306
// Starts a new depth-first search.
13131307
fn reset(&mut self, root: AnimationNodeIndex, node_count: usize) {

crates/bevy_ecs/macros/src/lib.rs

Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -180,6 +180,85 @@ pub fn derive_bundle(input: TokenStream) -> TokenStream {
180180
})
181181
}
182182

183+
#[proc_macro_derive(VisitEntitiesMut, attributes(visit_entities))]
184+
pub fn derive_visit_entities_mut(input: TokenStream) -> TokenStream {
185+
let ast = parse_macro_input!(input as DeriveInput);
186+
let ecs_path = bevy_ecs_path();
187+
188+
let named_fields = match get_struct_fields(&ast.data) {
189+
Ok(fields) => fields,
190+
Err(e) => return e.into_compile_error().into(),
191+
};
192+
193+
let field = named_fields
194+
.iter()
195+
.filter_map(|field| {
196+
if let Some(attr) = field
197+
.attrs
198+
.iter()
199+
.find(|a| a.path().is_ident("visit_entities"))
200+
{
201+
let ignore = attr.parse_nested_meta(|meta| {
202+
if meta.path.is_ident("ignore") {
203+
Ok(())
204+
} else {
205+
Err(meta.error("Invalid visit_entities attribute. Use `ignore`"))
206+
}
207+
});
208+
return match ignore {
209+
Ok(()) => None,
210+
Err(e) => Some(Err(e)),
211+
};
212+
}
213+
Some(Ok(field))
214+
})
215+
.map(|res| res.map(|field| field.ident.as_ref()))
216+
.collect::<Result<Vec<_>, _>>();
217+
218+
let field = match field {
219+
Ok(field) => field,
220+
Err(e) => return e.into_compile_error().into(),
221+
};
222+
223+
if field.is_empty() {
224+
return syn::Error::new(
225+
ast.span(),
226+
"Invalid `VisitEntitiesMut` type: at least one field",
227+
)
228+
.into_compile_error()
229+
.into();
230+
}
231+
232+
let field_access = field
233+
.iter()
234+
.enumerate()
235+
.map(|(n, f)| {
236+
if let Some(ident) = f {
237+
quote! {
238+
self.#ident
239+
}
240+
} else {
241+
let idx = Index::from(n);
242+
quote! {
243+
self.#idx
244+
}
245+
}
246+
})
247+
.collect::<Vec<_>>();
248+
249+
let generics = ast.generics;
250+
let (impl_generics, ty_generics, _) = generics.split_for_impl();
251+
let struct_name = &ast.ident;
252+
253+
TokenStream::from(quote! {
254+
impl #impl_generics #ecs_path::entity::VisitEntitiesMut for #struct_name #ty_generics {
255+
fn visit_entities_mut<F: FnMut(&mut Entity)>(&mut self, mut f: F) {
256+
#(#field_access.visit_entities_mut(&mut f);)*
257+
}
258+
}
259+
})
260+
}
261+
183262
#[proc_macro_derive(VisitEntities, attributes(visit_entities))]
184263
pub fn derive_visit_entities(input: TokenStream) -> TokenStream {
185264
let ast = parse_macro_input!(input as DeriveInput);

crates/bevy_ecs/src/entity/map_entities.rs

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ use crate::{
44
world::World,
55
};
66

7-
use super::EntityHashMap;
7+
use super::{EntityHashMap, VisitEntitiesMut};
88

99
/// Operation to map all contained [`Entity`] fields in a type to new values.
1010
///
@@ -45,6 +45,14 @@ pub trait MapEntities {
4545
fn map_entities<M: EntityMapper>(&mut self, entity_mapper: &mut M);
4646
}
4747

48+
impl<T: VisitEntitiesMut> MapEntities for T {
49+
fn map_entities<M: EntityMapper>(&mut self, entity_mapper: &mut M) {
50+
self.visit_entities_mut(|entity| {
51+
*entity = entity_mapper.map_entity(*entity);
52+
});
53+
}
54+
}
55+
4856
/// An implementor of this trait knows how to map an [`Entity`] into another [`Entity`].
4957
///
5058
/// Usually this is done by using an [`EntityHashMap<Entity>`] to map source entities

crates/bevy_ecs/src/entity/visit_entities.rs

Lines changed: 27 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
pub use bevy_ecs_macros::VisitEntities;
1+
pub use bevy_ecs_macros::{VisitEntities, VisitEntitiesMut};
22

33
use crate::entity::Entity;
44

@@ -28,6 +28,32 @@ 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)]
3258
mod tests {
3359
use crate::{self as bevy_ecs, entity::Entities};

crates/bevy_ecs/src/reflect/mod.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ pub use entity_commands::ReflectCommandExt;
2626
pub use from_world::{ReflectFromWorld, ReflectFromWorldFns};
2727
pub use map_entities::{ReflectMapEntities, ReflectMapEntitiesResource};
2828
pub use resource::{ReflectResource, ReflectResourceFns};
29-
pub use visit_entities::ReflectVisitEntities;
29+
pub use visit_entities::{ReflectVisitEntities, ReflectVisitEntitiesMut};
3030

3131
/// A [`Resource`] storing [`TypeRegistry`] for
3232
/// type registrations relevant to a whole app.

crates/bevy_ecs/src/reflect/visit_entities.rs

Lines changed: 34 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
use crate::entity::{Entity, VisitEntities};
1+
use crate::entity::{Entity, VisitEntities, VisitEntitiesMut};
22
use bevy_reflect::{FromReflect, FromType, PartialReflect};
33

44
/// For a reflected value, apply an operation to all contained entities.
@@ -27,3 +27,36 @@ impl<C: FromReflect + VisitEntities> FromType<C> for ReflectVisitEntities {
2727
}
2828
}
2929
}
30+
31+
/// For a reflected value, apply an operation to mutable references to all
32+
/// contained entities.
33+
///
34+
/// See [`VisitEntitiesMut`] for more details.
35+
#[derive(Clone)]
36+
pub struct ReflectVisitEntitiesMut {
37+
visit_entities_mut: fn(&mut dyn PartialReflect, &mut dyn FnMut(&mut Entity)),
38+
}
39+
40+
impl ReflectVisitEntitiesMut {
41+
/// A general method for applying an operation to all entities in a
42+
/// reflected component.
43+
pub fn visit_entities(
44+
&self,
45+
component: &mut dyn PartialReflect,
46+
f: &mut dyn FnMut(&mut Entity),
47+
) {
48+
(self.visit_entities_mut)(component, f);
49+
}
50+
}
51+
52+
impl<C: FromReflect + VisitEntitiesMut> FromType<C> for ReflectVisitEntitiesMut {
53+
fn from_type() -> Self {
54+
ReflectVisitEntitiesMut {
55+
visit_entities_mut: |component, f| {
56+
let mut concrete = C::from_reflect(component).unwrap();
57+
concrete.visit_entities_mut(f);
58+
component.apply(&concrete);
59+
},
60+
}
61+
}
62+
}

crates/bevy_hierarchy/src/components/children.rs

Lines changed: 11 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,11 @@
11
#[cfg(feature = "reflect")]
22
use bevy_ecs::reflect::{
33
ReflectComponent, ReflectFromWorld, ReflectMapEntities, ReflectVisitEntities,
4+
ReflectVisitEntitiesMut,
45
};
56
use bevy_ecs::{
67
component::Component,
7-
entity::{Entity, EntityMapper, MapEntities},
8+
entity::{Entity, VisitEntitiesMut},
89
prelude::FromWorld,
910
world::World,
1011
};
@@ -24,22 +25,21 @@ use smallvec::SmallVec;
2425
/// [`Query`]: bevy_ecs::system::Query
2526
/// [`Parent`]: crate::components::parent::Parent
2627
/// [`BuildChildren::with_children`]: crate::child_builder::BuildChildren::with_children
27-
#[derive(Component, Debug)]
28+
#[derive(Component, Debug, VisitEntitiesMut)]
2829
#[cfg_attr(feature = "reflect", derive(bevy_reflect::Reflect))]
2930
#[cfg_attr(
3031
feature = "reflect",
31-
reflect(Component, MapEntities, VisitEntities, Debug, FromWorld)
32+
reflect(
33+
Component,
34+
MapEntities,
35+
VisitEntities,
36+
VisitEntitiesMut,
37+
Debug,
38+
FromWorld
39+
)
3240
)]
3341
pub struct Children(pub(crate) SmallVec<[Entity; 8]>);
3442

35-
impl MapEntities for Children {
36-
fn map_entities<M: EntityMapper>(&mut self, entity_mapper: &mut M) {
37-
for entity in &mut self.0 {
38-
*entity = entity_mapper.map_entity(*entity);
39-
}
40-
}
41-
}
42-
4343
// TODO: We need to impl either FromWorld or Default so Children can be registered as Reflect.
4444
// This is because Reflect deserialize by creating an instance and apply a patch on top.
4545
// However Children should only ever be set with a real user-defined entities. Its worth looking

crates/bevy_hierarchy/src/components/parent.rs

Lines changed: 12 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,11 @@
11
#[cfg(feature = "reflect")]
22
use bevy_ecs::reflect::{
33
ReflectComponent, ReflectFromWorld, ReflectMapEntities, ReflectVisitEntities,
4+
ReflectVisitEntitiesMut,
45
};
56
use bevy_ecs::{
67
component::Component,
7-
entity::{Entity, EntityMapper, MapEntities, VisitEntities},
8+
entity::{Entity, VisitEntities, VisitEntitiesMut},
89
traversal::Traversal,
910
world::{FromWorld, World},
1011
};
@@ -23,11 +24,19 @@ use core::ops::Deref;
2324
/// [`Query`]: bevy_ecs::system::Query
2425
/// [`Children`]: super::children::Children
2526
/// [`BuildChildren::with_children`]: crate::child_builder::BuildChildren::with_children
26-
#[derive(Component, Debug, Eq, PartialEq, VisitEntities)]
27+
#[derive(Component, Debug, Eq, PartialEq, VisitEntities, VisitEntitiesMut)]
2728
#[cfg_attr(feature = "reflect", derive(bevy_reflect::Reflect))]
2829
#[cfg_attr(
2930
feature = "reflect",
30-
reflect(Component, MapEntities, VisitEntities, PartialEq, Debug, FromWorld)
31+
reflect(
32+
Component,
33+
MapEntities,
34+
VisitEntities,
35+
VisitEntitiesMut,
36+
PartialEq,
37+
Debug,
38+
FromWorld
39+
)
3140
)]
3241
pub struct Parent(pub(crate) Entity);
3342

@@ -61,12 +70,6 @@ impl FromWorld for Parent {
6170
}
6271
}
6372

64-
impl MapEntities for Parent {
65-
fn map_entities<M: EntityMapper>(&mut self, entity_mapper: &mut M) {
66-
self.0 = entity_mapper.map_entity(self.0);
67-
}
68-
}
69-
7073
impl Deref for Parent {
7174
type Target = Entity;
7275

crates/bevy_render/src/mesh/mesh/skinning.rs

Lines changed: 11 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,30 +1,29 @@
11
use bevy_asset::{Asset, Handle};
22
use bevy_ecs::{
33
component::Component,
4-
entity::{Entity, EntityMapper, MapEntities, VisitEntities},
4+
entity::{Entity, VisitEntities, VisitEntitiesMut},
55
prelude::ReflectComponent,
6-
reflect::{ReflectMapEntities, ReflectVisitEntities},
6+
reflect::{ReflectMapEntities, ReflectVisitEntities, ReflectVisitEntitiesMut},
77
};
88
use bevy_math::Mat4;
99
use bevy_reflect::prelude::*;
1010
use core::ops::Deref;
1111

12-
#[derive(Component, Debug, Default, Clone, Reflect, VisitEntities)]
13-
#[reflect(Component, MapEntities, VisitEntities, Default, Debug)]
12+
#[derive(Component, Debug, Default, Clone, Reflect, VisitEntities, VisitEntitiesMut)]
13+
#[reflect(
14+
Component,
15+
MapEntities,
16+
VisitEntities,
17+
VisitEntitiesMut,
18+
Default,
19+
Debug
20+
)]
1421
pub struct SkinnedMesh {
1522
#[visit_entities(ignore)]
1623
pub inverse_bindposes: Handle<SkinnedMeshInverseBindposes>,
1724
pub joints: Vec<Entity>,
1825
}
1926

20-
impl MapEntities for SkinnedMesh {
21-
fn map_entities<M: EntityMapper>(&mut self, entity_mapper: &mut M) {
22-
for joint in &mut self.joints {
23-
*joint = entity_mapper.map_entity(*joint);
24-
}
25-
}
26-
}
27-
2827
#[derive(Asset, TypePath, Debug)]
2928
pub struct SkinnedMeshInverseBindposes(Box<[Mat4]>);
3029

crates/bevy_scene/src/serde.rs

Lines changed: 2 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -515,7 +515,7 @@ mod tests {
515515
DynamicScene, DynamicSceneBuilder,
516516
};
517517
use bevy_ecs::{
518-
entity::{Entity, EntityHashMap, EntityMapper, MapEntities, VisitEntities},
518+
entity::{Entity, EntityHashMap, VisitEntities, VisitEntitiesMut},
519519
prelude::{Component, ReflectComponent, ReflectResource, Resource, World},
520520
query::{With, Without},
521521
reflect::{AppTypeRegistry, ReflectMapEntities},
@@ -584,16 +584,10 @@ mod tests {
584584
foo: i32,
585585
}
586586

587-
#[derive(Clone, Component, Reflect, PartialEq, VisitEntities)]
587+
#[derive(Clone, Component, Reflect, PartialEq, VisitEntities, VisitEntitiesMut)]
588588
#[reflect(Component, MapEntities, PartialEq)]
589589
struct MyEntityRef(Entity);
590590

591-
impl MapEntities for MyEntityRef {
592-
fn map_entities<M: EntityMapper>(&mut self, entity_mapper: &mut M) {
593-
self.0 = entity_mapper.map_entity(self.0);
594-
}
595-
}
596-
597591
impl FromWorld for MyEntityRef {
598592
fn from_world(_world: &mut World) -> Self {
599593
Self(Entity::PLACEHOLDER)

0 commit comments

Comments
 (0)