Skip to content

Commit 0a32450

Browse files
authored
Support using FilteredResources with ReflectResource. (#15624)
# Objective Support accessing resources using reflection when using `FilteredResources` in a dynamic system. This is similar to how components can be queried using reflection when using `FilteredEntityRef|Mut`. ## Solution Change `ReflectResource` from taking `&World` and `&mut World` to taking `impl Into<FilteredResources>` and `impl Into<FilteredResourcesMut>`, similar to how `ReflectComponent` takes `impl Into<FilteredEntityRef>` and `impl Into<FilteredEntityMut>`. There are `From` impls that ensure code passing `&World` and `&mut World` continues to work as before. ## Migration Guide If you are manually creating a `ReflectComponentFns` struct, the `reflect` function now takes `FilteredResources` instead `&World`, and there is a new `reflect_mut` function that takes `FilteredResourcesMut`.
1 parent d7fd00a commit 0a32450

File tree

2 files changed

+58
-10
lines changed

2 files changed

+58
-10
lines changed

crates/bevy_ecs/src/reflect/resource.rs

Lines changed: 24 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ use crate::{
88
change_detection::Mut,
99
component::ComponentId,
1010
resource::Resource,
11-
world::{unsafe_world_cell::UnsafeWorldCell, World},
11+
world::{unsafe_world_cell::UnsafeWorldCell, FilteredResources, FilteredResourcesMut, World},
1212
};
1313
use bevy_reflect::{FromReflect, FromType, PartialReflect, Reflect, TypePath, TypeRegistry};
1414

@@ -52,7 +52,9 @@ pub struct ReflectResourceFns {
5252
/// Function pointer implementing [`ReflectResource::remove()`].
5353
pub remove: fn(&mut World),
5454
/// Function pointer implementing [`ReflectResource::reflect()`].
55-
pub reflect: fn(&World) -> Option<&dyn Reflect>,
55+
pub reflect: for<'w> fn(FilteredResources<'w, '_>) -> Option<&'w dyn Reflect>,
56+
/// Function pointer implementing [`ReflectResource::reflect_mut()`].
57+
pub reflect_mut: for<'w> fn(FilteredResourcesMut<'w, '_>) -> Option<Mut<'w, dyn Reflect>>,
5658
/// Function pointer implementing [`ReflectResource::reflect_unchecked_mut()`].
5759
///
5860
/// # Safety
@@ -111,14 +113,23 @@ impl ReflectResource {
111113
}
112114

113115
/// Gets the value of this [`Resource`] type from the world as a reflected reference.
114-
pub fn reflect<'a>(&self, world: &'a World) -> Option<&'a dyn Reflect> {
115-
(self.0.reflect)(world)
116+
///
117+
/// Note that [`&World`](World) is a valid type for `resources`.
118+
pub fn reflect<'w, 's>(
119+
&self,
120+
resources: impl Into<FilteredResources<'w, 's>>,
121+
) -> Option<&'w dyn Reflect> {
122+
(self.0.reflect)(resources.into())
116123
}
117124

118125
/// Gets the value of this [`Resource`] type from the world as a mutable reflected reference.
119-
pub fn reflect_mut<'a>(&self, world: &'a mut World) -> Option<Mut<'a, dyn Reflect>> {
120-
// SAFETY: unique world access
121-
unsafe { (self.0.reflect_unchecked_mut)(world.as_unsafe_world_cell()) }
126+
///
127+
/// Note that [`&mut World`](World) is a valid type for `resources`.
128+
pub fn reflect_mut<'w, 's>(
129+
&self,
130+
resources: impl Into<FilteredResourcesMut<'w, 's>>,
131+
) -> Option<Mut<'w, dyn Reflect>> {
132+
(self.0.reflect_mut)(resources.into())
122133
}
123134

124135
/// # Safety
@@ -212,7 +223,12 @@ impl<R: Resource + FromReflect + TypePath> FromType<R> for ReflectResource {
212223
remove: |world| {
213224
world.remove_resource::<R>();
214225
},
215-
reflect: |world| world.get_resource::<R>().map(|res| res as &dyn Reflect),
226+
reflect: |world| world.get::<R>().map(|res| res.into_inner() as &dyn Reflect),
227+
reflect_mut: |world| {
228+
world
229+
.into_mut::<R>()
230+
.map(|res| res.map_unchanged(|value| value as &mut dyn Reflect))
231+
},
216232
reflect_unchecked_mut: |world| {
217233
// SAFETY: all usages of `reflect_unchecked_mut` guarantee that there is either a single mutable
218234
// reference or multiple immutable ones alive at any given point

crates/bevy_ecs/src/system/builder.rs

Lines changed: 34 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -715,9 +715,11 @@ mod tests {
715715
use crate::{
716716
entity::Entities,
717717
prelude::{Component, Query},
718+
reflect::ReflectResource,
718719
system::{Local, RunSystemOnce},
719720
};
720721
use alloc::vec;
722+
use bevy_reflect::{FromType, Reflect, ReflectRef};
721723

722724
use super::*;
723725

@@ -730,8 +732,11 @@ mod tests {
730732
#[derive(Component)]
731733
struct C;
732734

733-
#[derive(Resource, Default)]
734-
struct R;
735+
#[derive(Resource, Default, Reflect)]
736+
#[reflect(Resource)]
737+
struct R {
738+
foo: usize,
739+
}
735740

736741
fn local_system(local: Local<u64>) -> u64 {
737742
*local
@@ -1071,4 +1076,31 @@ mod tests {
10711076
.build_state(&mut world)
10721077
.build_system(|_r: ResMut<R>, _fr: FilteredResourcesMut| {});
10731078
}
1079+
1080+
#[test]
1081+
fn filtered_resource_reflect() {
1082+
let mut world = World::new();
1083+
world.insert_resource(R { foo: 7 });
1084+
1085+
let system = (FilteredResourcesParamBuilder::new(|builder| {
1086+
builder.add_read::<R>();
1087+
}),)
1088+
.build_state(&mut world)
1089+
.build_system(|res: FilteredResources| {
1090+
let reflect_resource = <ReflectResource as FromType<R>>::from_type();
1091+
let ReflectRef::Struct(reflect_struct) =
1092+
reflect_resource.reflect(res).unwrap().reflect_ref()
1093+
else {
1094+
panic!()
1095+
};
1096+
*reflect_struct
1097+
.field("foo")
1098+
.unwrap()
1099+
.try_downcast_ref::<usize>()
1100+
.unwrap()
1101+
});
1102+
1103+
let output = world.run_system_once(system).unwrap();
1104+
assert_eq!(output, 7);
1105+
}
10741106
}

0 commit comments

Comments
 (0)