bevy_ecs/reflect/resource.rs
1//! Definitions for [`Resource`] reflection.
2//!
3//! # Architecture
4//!
5//! See the module doc for [`crate::reflect::component`].
6
7use crate::{
8 change_detection::Mut,
9 component::ComponentId,
10 resource::Resource,
11 world::{
12 error::ResourceFetchError, unsafe_world_cell::UnsafeWorldCell, FilteredResources,
13 FilteredResourcesMut, World,
14 },
15};
16use bevy_reflect::{FromReflect, FromType, PartialReflect, Reflect, TypePath, TypeRegistry};
17
18use super::from_reflect_with_fallback;
19
20/// A struct used to operate on reflected [`Resource`] of a type.
21///
22/// A [`ReflectResource`] for type `T` can be obtained via
23/// [`bevy_reflect::TypeRegistration::data`].
24#[derive(Clone)]
25pub struct ReflectResource(ReflectResourceFns);
26
27/// The raw function pointers needed to make up a [`ReflectResource`].
28///
29/// This is used when creating custom implementations of [`ReflectResource`] with
30/// [`ReflectResource::new()`].
31///
32/// > **Note:**
33/// > Creating custom implementations of [`ReflectResource`] is an advanced feature that most users
34/// > will not need.
35/// > Usually a [`ReflectResource`] is created for a type by deriving [`Reflect`]
36/// > and adding the `#[reflect(Resource)]` attribute.
37/// > After adding the component to the [`TypeRegistry`],
38/// > its [`ReflectResource`] can then be retrieved when needed.
39///
40/// Creating a custom [`ReflectResource`] may be useful if you need to create new resource types at
41/// runtime, for example, for scripting implementations.
42///
43/// By creating a custom [`ReflectResource`] and inserting it into a type's
44/// [`TypeRegistration`][bevy_reflect::TypeRegistration],
45/// you can modify the way that reflected resources of that type will be inserted into the bevy
46/// world.
47#[derive(Clone)]
48pub struct ReflectResourceFns {
49 /// Function pointer implementing [`ReflectResource::insert()`].
50 pub insert: fn(&mut World, &dyn PartialReflect, &TypeRegistry),
51 /// Function pointer implementing [`ReflectResource::apply()`].
52 pub apply: fn(&mut World, &dyn PartialReflect),
53 /// Function pointer implementing [`ReflectResource::apply_or_insert()`].
54 pub apply_or_insert: fn(&mut World, &dyn PartialReflect, &TypeRegistry),
55 /// Function pointer implementing [`ReflectResource::remove()`].
56 pub remove: fn(&mut World),
57 /// Function pointer implementing [`ReflectResource::reflect()`].
58 pub reflect:
59 for<'w> fn(FilteredResources<'w, '_>) -> Result<&'w dyn Reflect, ResourceFetchError>,
60 /// Function pointer implementing [`ReflectResource::reflect_mut()`].
61 pub reflect_mut: for<'w> fn(
62 FilteredResourcesMut<'w, '_>,
63 ) -> Result<Mut<'w, dyn Reflect>, ResourceFetchError>,
64 /// Function pointer implementing [`ReflectResource::reflect_unchecked_mut()`].
65 ///
66 /// # Safety
67 /// The function may only be called with an [`UnsafeWorldCell`] that can be used to mutably access the relevant resource.
68 pub reflect_unchecked_mut: unsafe fn(UnsafeWorldCell<'_>) -> Option<Mut<'_, dyn Reflect>>,
69 /// Function pointer implementing [`ReflectResource::copy()`].
70 pub copy: fn(&World, &mut World, &TypeRegistry),
71 /// Function pointer implementing [`ReflectResource::register_resource()`].
72 pub register_resource: fn(&mut World) -> ComponentId,
73}
74
75impl ReflectResourceFns {
76 /// Get the default set of [`ReflectResourceFns`] for a specific resource type using its
77 /// [`FromType`] implementation.
78 ///
79 /// This is useful if you want to start with the default implementation before overriding some
80 /// of the functions to create a custom implementation.
81 pub fn new<T: Resource + FromReflect + TypePath>() -> Self {
82 <ReflectResource as FromType<T>>::from_type().0
83 }
84}
85
86impl ReflectResource {
87 /// Insert a reflected [`Resource`] into the world like [`insert()`](World::insert_resource).
88 pub fn insert(
89 &self,
90 world: &mut World,
91 resource: &dyn PartialReflect,
92 registry: &TypeRegistry,
93 ) {
94 (self.0.insert)(world, resource, registry);
95 }
96
97 /// Uses reflection to set the value of this [`Resource`] type in the world to the given value.
98 ///
99 /// # Panics
100 ///
101 /// Panics if there is no [`Resource`] of the given type.
102 pub fn apply(&self, world: &mut World, resource: &dyn PartialReflect) {
103 (self.0.apply)(world, resource);
104 }
105
106 /// Uses reflection to set the value of this [`Resource`] type in the world to the given value or insert a new one if it does not exist.
107 pub fn apply_or_insert(
108 &self,
109 world: &mut World,
110 resource: &dyn PartialReflect,
111 registry: &TypeRegistry,
112 ) {
113 (self.0.apply_or_insert)(world, resource, registry);
114 }
115
116 /// Removes this [`Resource`] type from the world. Does nothing if it doesn't exist.
117 pub fn remove(&self, world: &mut World) {
118 (self.0.remove)(world);
119 }
120
121 /// Gets the value of this [`Resource`] type from the world as a reflected reference.
122 ///
123 /// Note that [`&World`](World) is a valid type for `resources`.
124 pub fn reflect<'w, 's>(
125 &self,
126 resources: impl Into<FilteredResources<'w, 's>>,
127 ) -> Result<&'w dyn Reflect, ResourceFetchError> {
128 (self.0.reflect)(resources.into())
129 }
130
131 /// Gets the value of this [`Resource`] type from the world as a mutable reflected reference.
132 ///
133 /// Note that [`&mut World`](World) is a valid type for `resources`.
134 pub fn reflect_mut<'w, 's>(
135 &self,
136 resources: impl Into<FilteredResourcesMut<'w, 's>>,
137 ) -> Result<Mut<'w, dyn Reflect>, ResourceFetchError> {
138 (self.0.reflect_mut)(resources.into())
139 }
140
141 /// # Safety
142 /// This method does not prevent you from having two mutable pointers to the same data,
143 /// violating Rust's aliasing rules. To avoid this:
144 /// * Only call this method with an [`UnsafeWorldCell`] which can be used to mutably access the resource.
145 /// * Don't call this method more than once in the same scope for a given [`Resource`].
146 pub unsafe fn reflect_unchecked_mut<'w>(
147 &self,
148 world: UnsafeWorldCell<'w>,
149 ) -> Option<Mut<'w, dyn Reflect>> {
150 // SAFETY: caller promises to uphold uniqueness guarantees
151 unsafe { (self.0.reflect_unchecked_mut)(world) }
152 }
153
154 /// Gets the value of this [`Resource`] type from `source_world` and [applies](Self::apply()) it to the value of this [`Resource`] type in `destination_world`.
155 ///
156 /// # Panics
157 ///
158 /// Panics if there is no [`Resource`] of the given type.
159 pub fn copy(
160 &self,
161 source_world: &World,
162 destination_world: &mut World,
163 registry: &TypeRegistry,
164 ) {
165 (self.0.copy)(source_world, destination_world, registry);
166 }
167
168 /// Register the type of this [`Resource`] in [`World`], returning the [`ComponentId`]
169 pub fn register_resource(&self, world: &mut World) -> ComponentId {
170 (self.0.register_resource)(world)
171 }
172
173 /// Create a custom implementation of [`ReflectResource`].
174 ///
175 /// This is an advanced feature,
176 /// useful for scripting implementations,
177 /// that should not be used by most users
178 /// unless you know what you are doing.
179 ///
180 /// Usually you should derive [`Reflect`] and add the `#[reflect(Resource)]` component
181 /// to generate a [`ReflectResource`] implementation automatically.
182 ///
183 /// See [`ReflectResourceFns`] for more information.
184 pub fn new(&self, fns: ReflectResourceFns) -> Self {
185 Self(fns)
186 }
187
188 /// The underlying function pointers implementing methods on `ReflectResource`.
189 ///
190 /// This is useful when you want to keep track locally of an individual
191 /// function pointer.
192 ///
193 /// Calling [`TypeRegistry::get`] followed by
194 /// [`TypeRegistration::data::<ReflectResource>`] can be costly if done several
195 /// times per frame. Consider cloning [`ReflectResource`] and keeping it
196 /// between frames, cloning a `ReflectResource` is very cheap.
197 ///
198 /// If you only need a subset of the methods on `ReflectResource`,
199 /// use `fn_pointers` to get the underlying [`ReflectResourceFns`]
200 /// and copy the subset of function pointers you care about.
201 ///
202 /// [`TypeRegistration::data::<ReflectResource>`]: bevy_reflect::TypeRegistration::data
203 /// [`TypeRegistry::get`]: bevy_reflect::TypeRegistry::get
204 pub fn fn_pointers(&self) -> &ReflectResourceFns {
205 &self.0
206 }
207}
208
209impl<R: Resource + FromReflect + TypePath> FromType<R> for ReflectResource {
210 fn from_type() -> Self {
211 ReflectResource(ReflectResourceFns {
212 insert: |world, reflected_resource, registry| {
213 let resource = from_reflect_with_fallback::<R>(reflected_resource, world, registry);
214 world.insert_resource(resource);
215 },
216 apply: |world, reflected_resource| {
217 let mut resource = world.resource_mut::<R>();
218 resource.apply(reflected_resource);
219 },
220 apply_or_insert: |world, reflected_resource, registry| {
221 if let Some(mut resource) = world.get_resource_mut::<R>() {
222 resource.apply(reflected_resource);
223 } else {
224 let resource =
225 from_reflect_with_fallback::<R>(reflected_resource, world, registry);
226 world.insert_resource(resource);
227 }
228 },
229 remove: |world| {
230 world.remove_resource::<R>();
231 },
232 reflect: |world| world.get::<R>().map(|res| res.into_inner() as &dyn Reflect),
233 reflect_mut: |world| {
234 world
235 .into_mut::<R>()
236 .map(|res| res.map_unchanged(|value| value as &mut dyn Reflect))
237 },
238 reflect_unchecked_mut: |world| {
239 // SAFETY: all usages of `reflect_unchecked_mut` guarantee that there is either a single mutable
240 // reference or multiple immutable ones alive at any given point
241 let res = unsafe { world.get_resource_mut::<R>() };
242 res.map(|res| res.map_unchanged(|value| value as &mut dyn Reflect))
243 },
244 copy: |source_world, destination_world, registry| {
245 let source_resource = source_world.resource::<R>();
246 let destination_resource =
247 from_reflect_with_fallback::<R>(source_resource, destination_world, registry);
248 destination_world.insert_resource(destination_resource);
249 },
250
251 register_resource: |world: &mut World| -> ComponentId {
252 world.register_resource::<R>()
253 },
254 })
255 }
256}