Skip to main content

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}