bevy_ecs/world/filtered_resource.rs
1use crate::{
2 change_detection::{ComponentTicksMut, ComponentTicksRef, Mut, MutUntyped, Ref, Tick},
3 component::ComponentId,
4 query::Access,
5 resource::Resource,
6 world::{unsafe_world_cell::UnsafeWorldCell, World},
7};
8use bevy_ptr::Ptr;
9
10use super::error::ResourceFetchError;
11
12/// Provides read-only access to a set of [`Resource`]s defined by the contained [`Access`].
13///
14/// Use [`FilteredResourcesMut`] if you need mutable access to some resources.
15///
16/// To be useful as a [`SystemParam`](crate::system::SystemParam),
17/// this must be configured using a [`FilteredResourcesParamBuilder`](crate::system::FilteredResourcesParamBuilder)
18/// to build the system using a [`SystemParamBuilder`](crate::prelude::SystemParamBuilder).
19///
20/// # Examples
21///
22/// ```
23/// # use bevy_ecs::{prelude::*, system::*};
24/// #
25/// # #[derive(Default, Resource)]
26/// # struct A;
27/// #
28/// # #[derive(Default, Resource)]
29/// # struct B;
30/// #
31/// # #[derive(Default, Resource)]
32/// # struct C;
33/// #
34/// # let mut world = World::new();
35/// // Use `FilteredResourcesParamBuilder` to declare access to resources.
36/// let system = (FilteredResourcesParamBuilder::new(|builder| {
37/// builder.add_read::<B>().add_read::<C>();
38/// }),)
39/// .build_state(&mut world)
40/// .build_system(resource_system);
41///
42/// world.init_resource::<A>();
43/// world.init_resource::<C>();
44///
45/// fn resource_system(res: FilteredResources) {
46/// // The resource exists, but we have no access, so we can't read it.
47/// assert!(res.get::<A>().is_err());
48/// // The resource doesn't exist, so we can't read it.
49/// assert!(res.get::<B>().is_err());
50/// // The resource exists and we have access, so we can read it.
51/// let c = res.get::<C>().unwrap();
52/// // The type parameter can be left out if it can be determined from use.
53/// let c: Ref<C> = res.get().unwrap();
54/// }
55/// #
56/// # world.run_system_once(system);
57/// ```
58///
59/// This can be used alongside ordinary [`Res`](crate::system::Res) and [`ResMut`](crate::system::ResMut) parameters if they do not conflict.
60///
61/// ```
62/// # use bevy_ecs::{prelude::*, system::*};
63/// #
64/// # #[derive(Default, Resource)]
65/// # struct A;
66/// #
67/// # #[derive(Default, Resource)]
68/// # struct B;
69/// #
70/// # let mut world = World::new();
71/// # world.init_resource::<A>();
72/// # world.init_resource::<B>();
73/// #
74/// let system = (
75/// FilteredResourcesParamBuilder::new(|builder| {
76/// builder.add_read::<A>();
77/// }),
78/// ParamBuilder,
79/// ParamBuilder,
80/// )
81/// .build_state(&mut world)
82/// .build_system(resource_system);
83///
84/// // Read access to A does not conflict with read access to A or write access to B.
85/// fn resource_system(filtered: FilteredResources, res_a: Res<A>, res_mut_b: ResMut<B>) {
86/// let res_a_2: Ref<A> = filtered.get::<A>().unwrap();
87/// }
88/// #
89/// # world.run_system_once(system);
90/// ```
91///
92/// But it will conflict if it tries to read the same resource that another parameter writes.
93///
94/// ```should_panic
95/// # use bevy_ecs::{prelude::*, system::*};
96/// #
97/// # #[derive(Default, Resource)]
98/// # struct A;
99/// #
100/// # let mut world = World::new();
101/// # world.init_resource::<A>();
102/// #
103/// let system = (
104/// FilteredResourcesParamBuilder::new(|builder| {
105/// builder.add_read::<A>();
106/// }),
107/// ParamBuilder,
108/// )
109/// .build_state(&mut world)
110/// .build_system(invalid_resource_system);
111///
112/// // Read access to A conflicts with write access to A.
113/// fn invalid_resource_system(filtered: FilteredResources, res_mut_a: ResMut<A>) { }
114/// #
115/// # world.run_system_once(system);
116/// ```
117#[derive(Clone, Copy)]
118pub struct FilteredResources<'w, 's> {
119 world: UnsafeWorldCell<'w>,
120 access: &'s Access,
121 last_run: Tick,
122 this_run: Tick,
123}
124
125impl<'w, 's> FilteredResources<'w, 's> {
126 /// Creates a new [`FilteredResources`].
127 /// # Safety
128 /// It is the callers responsibility to ensure that nothing else may access the any resources in the `world` in a way that conflicts with `access`.
129 pub(crate) unsafe fn new(
130 world: UnsafeWorldCell<'w>,
131 access: &'s Access,
132 last_run: Tick,
133 this_run: Tick,
134 ) -> Self {
135 Self {
136 world,
137 access,
138 last_run,
139 this_run,
140 }
141 }
142
143 /// Returns a reference to the underlying [`Access`].
144 pub fn access(&self) -> &Access {
145 self.access
146 }
147
148 /// Returns `true` if the `FilteredResources` has access to the given resource.
149 /// Note that [`Self::get()`] may still return `Err` if the resource does not exist.
150 pub fn has_read<R: Resource>(&self) -> bool {
151 let component_id = self.world.components().component_id::<R>();
152 component_id.is_some_and(|component_id| self.access.has_read(component_id))
153 }
154
155 /// Gets a reference to the resource of the given type if it exists and the `FilteredResources` has access to it.
156 pub fn get<R: Resource>(&self) -> Result<Ref<'w, R>, ResourceFetchError> {
157 let component_id = self
158 .world
159 .components()
160 .valid_component_id::<R>()
161 .ok_or(ResourceFetchError::NotRegistered)?;
162 if !self.access.has_read(component_id) {
163 return Err(ResourceFetchError::NoResourceAccess(component_id));
164 }
165
166 // SAFETY: We have read access to this resource
167 let (value, ticks) = unsafe { self.world.get_resource_with_ticks(component_id) }
168 .ok_or(ResourceFetchError::DoesNotExist(component_id))?;
169
170 Ok(Ref {
171 // SAFETY: `component_id` was obtained from the type ID of `R`.
172 value: unsafe { value.deref() },
173 // SAFETY: We have read access to the resource, so no mutable reference can exist.
174 ticks: unsafe {
175 ComponentTicksRef::from_tick_cells(ticks, self.last_run, self.this_run)
176 },
177 })
178 }
179
180 /// Gets a pointer to the resource with the given [`ComponentId`] if it exists and the `FilteredResources` has access to it.
181 pub fn get_by_id(&self, component_id: ComponentId) -> Result<Ptr<'w>, ResourceFetchError> {
182 if !self.access.has_read(component_id) {
183 return Err(ResourceFetchError::NoResourceAccess(component_id));
184 }
185 // SAFETY: We have read access to this resource
186 unsafe { self.world.get_resource_by_id(component_id) }
187 .ok_or(ResourceFetchError::DoesNotExist(component_id))
188 }
189}
190
191impl<'w, 's> From<FilteredResourcesMut<'w, 's>> for FilteredResources<'w, 's> {
192 fn from(resources: FilteredResourcesMut<'w, 's>) -> Self {
193 // SAFETY:
194 // - `FilteredResourcesMut` guarantees exclusive access to all resources in the new `FilteredResources`.
195 unsafe {
196 FilteredResources::new(
197 resources.world,
198 resources.access,
199 resources.last_run,
200 resources.this_run,
201 )
202 }
203 }
204}
205
206impl<'w, 's> From<&'w FilteredResourcesMut<'_, 's>> for FilteredResources<'w, 's> {
207 fn from(resources: &'w FilteredResourcesMut<'_, 's>) -> Self {
208 // SAFETY:
209 // - `FilteredResourcesMut` guarantees exclusive access to all components in the new `FilteredResources`.
210 unsafe {
211 FilteredResources::new(
212 resources.world,
213 resources.access,
214 resources.last_run,
215 resources.this_run,
216 )
217 }
218 }
219}
220
221impl<'w> From<&'w World> for FilteredResources<'w, 'static> {
222 fn from(value: &'w World) -> Self {
223 const READ_ALL_RESOURCES: &Access = const { &Access::new_read_all() };
224
225 let last_run = value.last_change_tick();
226 let this_run = value.read_change_tick();
227 // SAFETY: We have a reference to the entire world, so nothing else can alias with read access to all resources.
228 unsafe {
229 Self::new(
230 value.as_unsafe_world_cell_readonly(),
231 READ_ALL_RESOURCES,
232 last_run,
233 this_run,
234 )
235 }
236 }
237}
238
239impl<'w> From<&'w mut World> for FilteredResources<'w, 'static> {
240 fn from(value: &'w mut World) -> Self {
241 Self::from(&*value)
242 }
243}
244
245/// Provides mutable access to a set of [`Resource`]s defined by the contained [`Access`].
246///
247/// Use [`FilteredResources`] if you only need read-only access to resources.
248///
249/// To be useful as a [`SystemParam`](crate::system::SystemParam),
250/// this must be configured using a [`FilteredResourcesMutParamBuilder`](crate::system::FilteredResourcesMutParamBuilder)
251/// to build the system using a [`SystemParamBuilder`](crate::prelude::SystemParamBuilder).
252///
253/// # Examples
254///
255/// ```
256/// # use bevy_ecs::{prelude::*, system::*};
257/// #
258/// # #[derive(Default, Resource)]
259/// # struct A;
260/// #
261/// # #[derive(Default, Resource)]
262/// # struct B;
263/// #
264/// # #[derive(Default, Resource)]
265/// # struct C;
266/// #
267/// # #[derive(Default, Resource)]
268/// # struct D;
269/// #
270/// # let mut world = World::new();
271/// // Use `FilteredResourcesMutParamBuilder` to declare access to resources.
272/// let system = (FilteredResourcesMutParamBuilder::new(|builder| {
273/// builder.add_write::<B>().add_read::<C>().add_write::<D>();
274/// }),)
275/// .build_state(&mut world)
276/// .build_system(resource_system);
277///
278/// world.init_resource::<A>();
279/// world.init_resource::<C>();
280/// world.init_resource::<D>();
281///
282/// fn resource_system(mut res: FilteredResourcesMut) {
283/// // The resource exists, but we have no access, so we can't read it or write it.
284/// assert!(res.get::<A>().is_err());
285/// assert!(res.get_mut::<A>().is_err());
286/// // The resource doesn't exist, so we can't read it or write it.
287/// assert!(res.get::<B>().is_err());
288/// assert!(res.get_mut::<B>().is_err());
289/// // The resource exists and we have read access, so we can read it but not write it.
290/// let c = res.get::<C>().unwrap();
291/// assert!(res.get_mut::<C>().is_err());
292/// // The resource exists and we have write access, so we can read it or write it.
293/// let d = res.get::<D>().unwrap();
294/// let d = res.get_mut::<D>().unwrap();
295/// // The type parameter can be left out if it can be determined from use.
296/// let c: Ref<C> = res.get().unwrap();
297/// }
298/// #
299/// # world.run_system_once(system);
300/// ```
301///
302/// This can be used alongside ordinary [`Res`](crate::system::ResMut) and [`ResMut`](crate::system::ResMut) parameters if they do not conflict.
303///
304/// ```
305/// # use bevy_ecs::{prelude::*, system::*};
306/// #
307/// # #[derive(Default, Resource)]
308/// # struct A;
309/// #
310/// # #[derive(Default, Resource)]
311/// # struct B;
312/// #
313/// # #[derive(Default, Resource)]
314/// # struct C;
315/// #
316/// # let mut world = World::new();
317/// # world.init_resource::<A>();
318/// # world.init_resource::<B>();
319/// # world.init_resource::<C>();
320/// #
321/// let system = (
322/// FilteredResourcesMutParamBuilder::new(|builder| {
323/// builder.add_read::<A>().add_write::<B>();
324/// }),
325/// ParamBuilder,
326/// ParamBuilder,
327/// )
328/// .build_state(&mut world)
329/// .build_system(resource_system);
330///
331/// // Read access to A does not conflict with read access to A or write access to C.
332/// // Write access to B does not conflict with access to A or C.
333/// fn resource_system(mut filtered: FilteredResourcesMut, res_a: Res<A>, res_mut_c: ResMut<C>) {
334/// let res_a_2: Ref<A> = filtered.get::<A>().unwrap();
335/// let res_mut_b: Mut<B> = filtered.get_mut::<B>().unwrap();
336/// }
337/// #
338/// # world.run_system_once(system);
339/// ```
340///
341/// But it will conflict if it tries to read the same resource that another parameter writes,
342/// or write the same resource that another parameter reads.
343///
344/// ```should_panic
345/// # use bevy_ecs::{prelude::*, system::*};
346/// #
347/// # #[derive(Default, Resource)]
348/// # struct A;
349/// #
350/// # let mut world = World::new();
351/// # world.init_resource::<A>();
352/// #
353/// let system = (
354/// FilteredResourcesMutParamBuilder::new(|builder| {
355/// builder.add_write::<A>();
356/// }),
357/// ParamBuilder,
358/// )
359/// .build_state(&mut world)
360/// .build_system(invalid_resource_system);
361///
362/// // Read access to A conflicts with write access to A.
363/// fn invalid_resource_system(filtered: FilteredResourcesMut, res_a: Res<A>) { }
364/// #
365/// # world.run_system_once(system);
366/// ```
367pub struct FilteredResourcesMut<'w, 's> {
368 world: UnsafeWorldCell<'w>,
369 access: &'s Access,
370 last_run: Tick,
371 this_run: Tick,
372}
373
374impl<'w, 's> FilteredResourcesMut<'w, 's> {
375 /// Creates a new [`FilteredResources`].
376 /// # Safety
377 /// It is the callers responsibility to ensure that nothing else may access the any resources in the `world` in a way that conflicts with `access`.
378 pub(crate) unsafe fn new(
379 world: UnsafeWorldCell<'w>,
380 access: &'s Access,
381 last_run: Tick,
382 this_run: Tick,
383 ) -> Self {
384 Self {
385 world,
386 access,
387 last_run,
388 this_run,
389 }
390 }
391
392 /// Gets read-only access to all of the resources this `FilteredResourcesMut` can access.
393 pub fn as_readonly(&self) -> FilteredResources<'_, 's> {
394 FilteredResources::from(self)
395 }
396
397 /// Returns a new instance with a shorter lifetime.
398 /// This is useful if you have `&mut FilteredResourcesMut`, but you need `FilteredResourcesMut`.
399 pub fn reborrow(&mut self) -> FilteredResourcesMut<'_, 's> {
400 // SAFETY: We have exclusive access to this access for the duration of `'_`, so there cannot be anything else that conflicts.
401 unsafe { Self::new(self.world, self.access, self.last_run, self.this_run) }
402 }
403
404 /// Returns a reference to the underlying [`Access`].
405 pub fn access(&self) -> &Access {
406 self.access
407 }
408
409 /// Returns `true` if the `FilteredResources` has read access to the given resource.
410 /// Note that [`Self::get()`] may still return `Err` if the resource does not exist.
411 pub fn has_read<R: Resource>(&self) -> bool {
412 let component_id = self.world.components().component_id::<R>();
413 component_id.is_some_and(|component_id| self.access.has_read(component_id))
414 }
415
416 /// Returns `true` if the `FilteredResources` has write access to the given resource.
417 /// Note that [`Self::get_mut()`] may still return `Err` if the resource does not exist.
418 pub fn has_write<R: Resource>(&self) -> bool {
419 let component_id = self.world.components().component_id::<R>();
420 component_id.is_some_and(|component_id| self.access.has_write(component_id))
421 }
422
423 /// Gets a reference to the resource of the given type if it exists and the `FilteredResources` has access to it.
424 pub fn get<R: Resource>(&self) -> Result<Ref<'_, R>, ResourceFetchError> {
425 self.as_readonly().get()
426 }
427
428 /// Gets a pointer to the resource with the given [`ComponentId`] if it exists and the `FilteredResources` has access to it.
429 pub fn get_by_id(&self, component_id: ComponentId) -> Result<Ptr<'_>, ResourceFetchError> {
430 self.as_readonly().get_by_id(component_id)
431 }
432
433 /// Gets a mutable reference to the resource of the given type if it exists and the `FilteredResources` has access to it.
434 pub fn get_mut<R: Resource>(&mut self) -> Result<Mut<'_, R>, ResourceFetchError> {
435 // SAFETY: We have exclusive access to the resources in `access` for `'_`, and we shorten the returned lifetime to that.
436 unsafe { self.get_mut_unchecked() }
437 }
438
439 /// Gets a mutable pointer to the resource with the given [`ComponentId`] if it exists and the `FilteredResources` has access to it.
440 pub fn get_mut_by_id(
441 &mut self,
442 component_id: ComponentId,
443 ) -> Result<MutUntyped<'_>, ResourceFetchError> {
444 // SAFETY: We have exclusive access to the resources in `access` for `'_`, and we shorten the returned lifetime to that.
445 unsafe { self.get_mut_by_id_unchecked(component_id) }
446 }
447
448 /// Consumes self and gets mutable access to resource of the given type with the world `'w` lifetime if it exists and the `FilteredResources` has access to it.
449 pub fn into_mut<R: Resource>(mut self) -> Result<Mut<'w, R>, ResourceFetchError> {
450 // SAFETY: This consumes self, so we have exclusive access to the resources in `access` for the entirety of `'w`.
451 unsafe { self.get_mut_unchecked() }
452 }
453
454 /// Consumes self and gets mutable access to resource with the given [`ComponentId`] with the world `'w` lifetime if it exists and the `FilteredResources` has access to it.
455 pub fn into_mut_by_id(
456 mut self,
457 component_id: ComponentId,
458 ) -> Result<MutUntyped<'w>, ResourceFetchError> {
459 // SAFETY: This consumes self, so we have exclusive access to the resources in `access` for the entirety of `'w`.
460 unsafe { self.get_mut_by_id_unchecked(component_id) }
461 }
462
463 /// Gets a mutable pointer to the resource of the given type if it exists and the `FilteredResources` has access to it.
464 /// # Safety
465 /// It is the callers responsibility to ensure that there are no conflicting borrows of anything in `access` for the duration of the returned value.
466 unsafe fn get_mut_unchecked<R: Resource>(&mut self) -> Result<Mut<'w, R>, ResourceFetchError> {
467 let component_id = self
468 .world
469 .components()
470 .valid_component_id::<R>()
471 .ok_or(ResourceFetchError::NotRegistered)?;
472 // SAFETY: THe caller ensures that there are no conflicting borrows.
473 unsafe { self.get_mut_by_id_unchecked(component_id) }
474 // SAFETY: The underlying type of the resource is `R`.
475 .map(|ptr| unsafe { ptr.with_type::<R>() })
476 }
477
478 /// Gets a mutable pointer to the resource with the given [`ComponentId`] if it exists and the `FilteredResources` has access to it.
479 /// # Safety
480 /// It is the callers responsibility to ensure that there are no conflicting borrows of anything in `access` for the duration of the returned value.
481 unsafe fn get_mut_by_id_unchecked(
482 &mut self,
483 component_id: ComponentId,
484 ) -> Result<MutUntyped<'w>, ResourceFetchError> {
485 if !self.access.has_write(component_id) {
486 return Err(ResourceFetchError::NoResourceAccess(component_id));
487 }
488
489 // SAFETY: We have read access to this resource
490 let (value, ticks) = unsafe { self.world.get_resource_with_ticks(component_id) }
491 .ok_or(ResourceFetchError::DoesNotExist(component_id))?;
492
493 // SAFETY: Resource is present, so its component info exists
494 let mutable = unsafe { self.world.components().get_info_unchecked(component_id) }.mutable();
495 if !mutable {
496 return Err(ResourceFetchError::Immutable(component_id));
497 }
498
499 Ok(MutUntyped {
500 // SAFETY: We have exclusive access to the underlying storage.
501 value: unsafe { value.assert_unique() },
502 // SAFETY: We have exclusive access to the underlying storage.
503 ticks: unsafe {
504 ComponentTicksMut::from_tick_cells(ticks, self.last_run, self.this_run)
505 },
506 })
507 }
508}
509
510impl<'w> From<&'w mut World> for FilteredResourcesMut<'w, 'static> {
511 fn from(value: &'w mut World) -> Self {
512 const WRITE_ALL_RESOURCES: &Access = const { &Access::new_write_all() };
513
514 let last_run = value.last_change_tick();
515 let this_run = value.change_tick();
516 // SAFETY: We have a mutable reference to the entire world, so nothing else can alias with mutable access to all resources.
517 unsafe {
518 Self::new(
519 value.as_unsafe_world_cell_readonly(),
520 WRITE_ALL_RESOURCES,
521 last_run,
522 this_run,
523 )
524 }
525 }
526}
527
528/// Builder struct to define the access for a [`FilteredResources`].
529///
530/// This is passed to a callback in [`FilteredResourcesParamBuilder`](crate::system::FilteredResourcesParamBuilder).
531pub struct FilteredResourcesBuilder<'w> {
532 world: &'w mut World,
533 access: Access,
534}
535
536impl<'w> FilteredResourcesBuilder<'w> {
537 /// Creates a new builder with no access.
538 pub fn new(world: &'w mut World) -> Self {
539 Self {
540 world,
541 access: Access::new(),
542 }
543 }
544
545 /// Returns a reference to the underlying [`Access`].
546 pub fn access(&self) -> &Access {
547 &self.access
548 }
549
550 /// Add accesses required to read all resources.
551 pub fn add_read_all(&mut self) -> &mut Self {
552 self.access.read_all();
553 self
554 }
555
556 /// Add accesses required to read the resource of the given type.
557 pub fn add_read<R: Resource>(&mut self) -> &mut Self {
558 let component_id = self
559 .world
560 .components_registrator()
561 .register_component::<R>();
562 self.add_read_by_id(component_id)
563 }
564
565 /// Add accesses required to read the resource with the given [`ComponentId`].
566 pub fn add_read_by_id(&mut self, component_id: ComponentId) -> &mut Self {
567 self.access.add_read(component_id);
568 self
569 }
570
571 /// Create an [`Access`] that represents the accesses of the builder.
572 pub fn build(self) -> Access {
573 self.access
574 }
575}
576
577/// Builder struct to define the access for a [`FilteredResourcesMut`].
578///
579/// This is passed to a callback in [`FilteredResourcesMutParamBuilder`](crate::system::FilteredResourcesMutParamBuilder).
580pub struct FilteredResourcesMutBuilder<'w> {
581 world: &'w mut World,
582 access: Access,
583}
584
585impl<'w> FilteredResourcesMutBuilder<'w> {
586 /// Creates a new builder with no access.
587 pub fn new(world: &'w mut World) -> Self {
588 Self {
589 world,
590 access: Access::new(),
591 }
592 }
593
594 /// Returns a reference to the underlying [`Access`].
595 pub fn access(&self) -> &Access {
596 &self.access
597 }
598
599 /// Add accesses required to read all resources.
600 pub fn add_read_all(&mut self) -> &mut Self {
601 self.access.read_all();
602 self
603 }
604
605 /// Add accesses required to read the resource of the given type.
606 pub fn add_read<R: Resource>(&mut self) -> &mut Self {
607 let component_id = self
608 .world
609 .components_registrator()
610 .register_component::<R>();
611 self.add_read_by_id(component_id)
612 }
613
614 /// Add accesses required to read the resource with the given [`ComponentId`].
615 pub fn add_read_by_id(&mut self, component_id: ComponentId) -> &mut Self {
616 self.access.add_read(component_id);
617 self
618 }
619
620 /// Add accesses required to get mutable access to all resources.
621 pub fn add_write_all(&mut self) -> &mut Self {
622 self.access.write_all();
623 self
624 }
625
626 /// Add accesses required to get mutable access to the resource of the given type.
627 pub fn add_write<R: Resource>(&mut self) -> &mut Self {
628 let component_id = self
629 .world
630 .components_registrator()
631 .register_component::<R>();
632 self.add_write_by_id(component_id)
633 }
634
635 /// Add accesses required to get mutable access to the resource with the given [`ComponentId`].
636 pub fn add_write_by_id(&mut self, component_id: ComponentId) -> &mut Self {
637 self.access.add_write(component_id);
638 self
639 }
640
641 /// Create an [`Access`] that represents the accesses of the builder.
642 pub fn build(self) -> Access {
643 self.access
644 }
645}