Skip to main content

bevy_ecs/system/
builder.rs

1use alloc::{boxed::Box, vec::Vec};
2use bevy_platform::cell::SyncCell;
3use bevy_utils::prelude::DebugName;
4use smallvec::SmallVec;
5use variadics_please::all_tuples;
6
7use crate::{
8    change_detection::{CheckChangeTicks, Tick},
9    component::Mutable,
10    prelude::QueryBuilder,
11    query::{FilteredAccessSet, QueryData, QueryFilter, QueryState},
12    resource::Resource,
13    system::{
14        DynSystemParam, DynSystemParamState, FromInput, FunctionSystem, If, IntoResult, IntoSystem,
15        Local, ParamSet, Query, ReadOnlySystem, System, SystemInput, SystemMeta, SystemParam,
16        SystemParamFunction, SystemParamValidationError,
17    },
18    world::{
19        unsafe_world_cell::UnsafeWorldCell, DeferredWorld, FilteredResources,
20        FilteredResourcesBuilder, FilteredResourcesMut, FilteredResourcesMutBuilder, FromWorld,
21        World,
22    },
23};
24use core::{fmt::Debug, marker::PhantomData, mem};
25
26use super::{Res, ResMut, RunSystemError, SystemState, SystemStateFlags};
27
28/// A builder that can create a [`SystemParam`].
29///
30/// ```
31/// # use bevy_ecs::{
32/// #     prelude::*,
33/// #     system::{SystemParam, ParamBuilder},
34/// # };
35/// # #[derive(Resource)]
36/// # struct R;
37/// #
38/// # #[derive(SystemParam)]
39/// # struct MyParam;
40/// #
41/// fn some_system(param: MyParam) {}
42///
43/// fn build_system(builder: impl SystemParamBuilder<MyParam> + 'static) {
44///     // To build a system, create a tuple of `SystemParamBuilder`s
45///     // with a builder for each parameter.
46///     // Note that the builder for a system must be a tuple,
47///     // even if there is only one parameter.
48/// #   let _system: bevy_ecs::system::IntoBuilderSystem<fn(MyParam), (), (), _, _> =
49///     (builder,)
50///         .build_system(some_system);
51/// }
52///
53/// fn build_system_direct(builder: impl SystemParamBuilder<MyParam>) {
54///     let mut world = World::new();
55///     // You can also construct a system in two steps, first by
56///     // constructing a [`SystemState`] with `build_state` and
57///     // second by constructing the final system with `build_system`.
58///     // This can be useful in cases that require type inference
59///     // for function parameters (like closures!), since normal
60///     // `build_system` requires explicitly specifying all parameter
61///     // types. See `build_closure_system_infer/explicit` below for more
62///     // info.
63///     (builder,)
64///         .build_state(&mut world)
65///         .build_system(some_system);
66/// }
67///
68/// fn build_closure_system_infer(builder: impl SystemParamBuilder<MyParam>) {
69///     let mut world = World::new();
70///     // Closures can be used in addition to named functions.
71///     // If a closure is used, the parameter types must all be inferred
72///     // from the builders, so you cannot use plain `ParamBuilder`.
73///     (builder, ParamBuilder::resource())
74///         .build_state(&mut world)
75///         .build_system(|param, res| {
76///             let param: MyParam = param;
77///             let res: Res<R> = res;
78///         });
79/// }
80///
81/// fn build_closure_system_explicit(builder: impl SystemParamBuilder<MyParam>) {
82///     let mut world = World::new();
83///     // Alternately, you can provide all types in the closure
84///     // parameter list and call `build_system()` normally.
85///     (builder, ParamBuilder::resource())
86///         .build_state(&mut world) // this line can be optionally omitted, since all the parameter types are explicit!
87///         .build_system(|param: MyParam, res: Res<R>| {});
88/// }
89/// ```
90///
91/// See the documentation for individual builders for more examples.
92///
93/// # List of Builders
94///
95/// [`ParamBuilder`] can be used for parameters that don't require any special building.
96/// Using a `ParamBuilder` will build the system parameter the same way it would be initialized in an ordinary system.
97///
98/// `ParamBuilder` also provides factory methods that return a `ParamBuilder` typed as `impl SystemParamBuilder<P>`
99/// for common system parameters that can be used to guide closure parameter inference.
100///
101/// [`QueryParamBuilder`] can build a [`Query`] to add additional filters,
102/// or to configure the components available to [`FilteredEntityRef`](crate::world::FilteredEntityRef) or [`FilteredEntityMut`](crate::world::FilteredEntityMut).
103/// You can also use a [`QueryState`] to build a [`Query`].
104///
105/// [`LocalBuilder`] can build a [`Local`] to supply the initial value for the `Local`.
106///
107/// [`FilteredResourcesParamBuilder`] can build a [`FilteredResources`],
108/// and [`FilteredResourcesMutParamBuilder`] can build a [`FilteredResourcesMut`],
109/// to configure the resources that can be accessed.
110///
111/// [`DynParamBuilder`] can build a [`DynSystemParam`] to determine the type of the inner parameter,
112/// and to supply any `SystemParamBuilder` it needs.
113///
114/// Tuples of builders can build tuples of parameters, one builder for each element.
115/// Note that since systems require a tuple as a parameter, the outer builder for a system will always be a tuple.
116///
117/// A [`Vec`] of builders can build a `Vec` of parameters, one builder for each element.
118///
119/// A [`ParamSetBuilder`] can build a [`ParamSet`].
120/// This can wrap either a tuple or a `Vec`, one builder for each element.
121///
122/// A custom system param created with `#[derive(SystemParam)]` can be buildable if it includes a `#[system_param(builder)]` attribute.
123/// See [the documentation for `SystemParam` derives](SystemParam#builders).
124///
125/// # Safety
126///
127/// The implementor must ensure that the state returned
128/// from [`SystemParamBuilder::build`] is valid for `P`.
129/// Note that the exact safety requirements depend on the implementation of [`SystemParam`],
130/// so if `Self` is not a local type then you must call [`SystemParam::init_state`]
131/// or another [`SystemParamBuilder::build`].
132pub unsafe trait SystemParamBuilder<P: SystemParam>: Sized {
133    /// Registers any [`World`] access used by this [`SystemParam`]
134    /// and creates a new instance of this param's [`State`](SystemParam::State).
135    fn build(self, world: &mut World) -> P::State;
136
137    /// Create a [`SystemState`] from a [`SystemParamBuilder`].
138    /// To create a system, call [`SystemState::build_system`] on the result.
139    fn build_state(self, world: &mut World) -> SystemState<P> {
140        SystemState::from_builder(world, self)
141    }
142
143    /// Create a [`System`] from a [`SystemParamBuilder`] directly.
144    ///
145    /// This method is useful in cases where type inference for
146    /// closure parameters isn't necessary, or where it's not
147    /// possible to call [`SystemState::build_system`] by passing
148    /// in an `&mut World`. Rather than constructing the system's
149    /// state immediately, this function returns a wrapper that
150    /// initializes the system state during the first run.
151    ///
152    /// Caveats:
153    /// - doesn't support parameter type inference.
154    /// - only works for 'static system param builder types.
155    ///
156    /// In cases where  either of these are required, call
157    /// [`SystemParamBuilder::build_state`] instead.
158    fn build_system<Marker, In, Out, Func>(
159        self,
160        func: Func,
161    ) -> IntoBuilderSystem<Marker, In, Out, Func, Self>
162    where
163        Self: 'static,
164        Func: SystemParamFunction<Marker, Param = P>,
165    {
166        IntoBuilderSystem::new(self, func)
167    }
168}
169
170/// A [`SystemParamBuilder`] for any [`SystemParam`] that uses its default initialization.
171///
172/// ## Example
173///
174/// ```
175/// # use bevy_ecs::{
176/// #     prelude::*,
177/// #     system::{SystemParam, ParamBuilder},
178/// # };
179/// #
180/// # #[derive(Component)]
181/// # struct A;
182/// #
183/// # #[derive(Resource)]
184/// # struct R;
185/// #
186/// # #[derive(SystemParam)]
187/// # struct MyParam;
188/// #
189/// # let mut world = World::new();
190/// # world.insert_resource(R);
191/// #
192/// fn my_system(res: Res<R>, param: MyParam, query: Query<&A>) {
193///     // ...
194/// }
195///
196/// let system = (
197///     // A plain ParamBuilder can build any parameter type.
198///     ParamBuilder,
199///     // The `of::<P>()` method returns a `ParamBuilder`
200///     // typed as `impl SystemParamBuilder<P>`.
201///     ParamBuilder::of::<MyParam>(),
202///     // The other factory methods return typed builders
203///     // for common parameter types.
204///     ParamBuilder::query::<&A>(),
205/// )
206///     .build_state(&mut world)
207///     .build_system(my_system);
208/// ```
209#[derive(Default, Debug, Clone)]
210pub struct ParamBuilder;
211
212// SAFETY: Calls `SystemParam::init_state`
213unsafe impl<P: SystemParam> SystemParamBuilder<P> for ParamBuilder {
214    fn build(self, world: &mut World) -> P::State {
215        P::init_state(world)
216    }
217}
218
219impl ParamBuilder {
220    /// Creates a [`SystemParamBuilder`] for any [`SystemParam`] that uses its default initialization.
221    pub fn of<T: SystemParam>() -> impl SystemParamBuilder<T> {
222        Self
223    }
224
225    /// Helper method for reading a [`Resource`] as a param, equivalent to `of::<Res<T>>()`
226    pub fn resource<'w, T: Resource>() -> impl SystemParamBuilder<Res<'w, T>> {
227        Self
228    }
229
230    /// Helper method for mutably accessing a [`Resource`] as a param, equivalent to `of::<ResMut<T>>()`
231    pub fn resource_mut<'w, T: Resource<Mutability = Mutable>>(
232    ) -> impl SystemParamBuilder<ResMut<'w, T>> {
233        Self
234    }
235
236    /// Helper method for adding a [`Local`] as a param, equivalent to `of::<Local<T>>()`
237    pub fn local<'s, T: FromWorld + Send + 'static>() -> impl SystemParamBuilder<Local<'s, T>> {
238        Self
239    }
240
241    /// Helper method for adding a [`Query`] as a param, equivalent to `of::<Query<D>>()`
242    pub fn query<'w, 's, D: QueryData + 'static>() -> impl SystemParamBuilder<Query<'w, 's, D, ()>>
243    {
244        Self
245    }
246
247    /// Helper method for adding a filtered [`Query`] as a param, equivalent to `of::<Query<D, F>>()`
248    pub fn query_filtered<'w, 's, D: QueryData + 'static, F: QueryFilter + 'static>(
249    ) -> impl SystemParamBuilder<Query<'w, 's, D, F>> {
250        Self
251    }
252}
253
254/// A marker type used to distinguish builder systems from plain function systems.
255#[doc(hidden)]
256pub struct IsBuilderSystem;
257
258/// An [`IntoSystem`] creating an instance of [`BuilderSystem`]
259pub struct IntoBuilderSystem<Marker, In, Out, Func, Builder>
260where
261    Func: SystemParamFunction<Marker>,
262    Builder: SystemParamBuilder<Func::Param>,
263{
264    builder: Builder,
265    func: Func,
266    _marker: PhantomData<fn(In) -> (Marker, Out)>,
267}
268
269impl<Marker, In, Out, Func, Builder> IntoBuilderSystem<Marker, In, Out, Func, Builder>
270where
271    Func: SystemParamFunction<Marker>,
272    Builder: SystemParamBuilder<Func::Param>,
273{
274    /// Returns a new [`IntoBuilderSystem`] given a system param builder and system function
275    pub fn new(builder: Builder, func: Func) -> Self {
276        Self {
277            builder,
278            func,
279            _marker: PhantomData,
280        }
281    }
282}
283
284impl<Marker, In, Out, Func, Builder> IntoSystem<In, Out, (IsBuilderSystem, Marker)>
285    for IntoBuilderSystem<Marker, In, Out, Func, Builder>
286where
287    Marker: 'static,
288    In: SystemInput + 'static,
289    Out: 'static,
290    Func: SystemParamFunction<Marker, In: FromInput<In>, Out: IntoResult<Out>>,
291    Builder: SystemParamBuilder<Func::Param> + Send + Sync + 'static,
292{
293    type System = BuilderSystem<Marker, In, Out, Func, Builder>;
294
295    fn into_system(this: Self) -> Self::System {
296        BuilderSystem::new(this.builder, this.func)
297    }
298}
299
300/// A [`System`] created from a [`SystemParamBuilder`] whose state is not
301/// initialized until the first run.
302pub struct BuilderSystem<Marker, In, Out, Func, Builder>
303where
304    Func: SystemParamFunction<Marker>,
305    Builder: SystemParamBuilder<Func::Param>,
306{
307    inner: BuilderSystemInner<Marker, In, Out, Func, Builder>,
308}
309
310impl<Marker, In, Out, Func, Builder> BuilderSystem<Marker, In, Out, Func, Builder>
311where
312    Func: SystemParamFunction<Marker>,
313    Builder: SystemParamBuilder<Func::Param>,
314{
315    /// Returns a new `BuilderSystem` given a system param builder and a system function
316    pub fn new(builder: Builder, func: Func) -> Self {
317        Self {
318            inner: BuilderSystemInner::Uninitialized {
319                builder,
320                func,
321                meta: SystemMeta::new::<Func>(),
322            },
323        }
324    }
325}
326
327enum BuilderSystemInner<Marker, In, Out, Func, Builder>
328where
329    Func: SystemParamFunction<Marker>,
330    Builder: SystemParamBuilder<Func::Param>,
331{
332    /// A properly initialized system whose state has been constructed
333    Initialized {
334        system: FunctionSystem<Marker, In, Out, Func>,
335    },
336    /// An uninitialized system, whose state hasn't been constructed from
337    /// the param builder yet
338    Uninitialized {
339        builder: Builder,
340        func: Func,
341        meta: SystemMeta,
342    },
343    /// This only exists as a variant to use with `mem::replace` in `initialize`.
344    /// If this state is ever observed outside `initialize`, then a `panic!`
345    /// interrupted initialization, leaving this system in an invalid state.
346    Invalid,
347}
348
349impl<Marker, In, Out, Func, Builder> System for BuilderSystem<Marker, In, Out, Func, Builder>
350where
351    Marker: 'static,
352    In: SystemInput + 'static,
353    Out: 'static,
354    Func: SystemParamFunction<Marker, In: FromInput<In>, Out: IntoResult<Out>>,
355    Builder: SystemParamBuilder<Func::Param> + Send + Sync + 'static,
356{
357    type In = In;
358
359    type Out = Out;
360
361    #[inline]
362    fn name(&self) -> DebugName {
363        match &self.inner {
364            BuilderSystemInner::Initialized { system } => system.name(),
365            BuilderSystemInner::Uninitialized { meta, .. } => meta.name().clone(),
366            BuilderSystemInner::Invalid => unreachable!(),
367        }
368    }
369
370    #[inline]
371    fn flags(&self) -> SystemStateFlags {
372        match &self.inner {
373            BuilderSystemInner::Initialized { system, .. } => system.flags(),
374            BuilderSystemInner::Uninitialized { meta, .. } => meta.flags(),
375            BuilderSystemInner::Invalid => unreachable!(),
376        }
377    }
378
379    #[inline]
380    unsafe fn run_unsafe(
381        &mut self,
382        input: super::SystemIn<'_, Self>,
383        world: UnsafeWorldCell,
384    ) -> Result<Self::Out, RunSystemError> {
385        match &mut self.inner {
386            // SAFETY: requirements upheld by the caller.
387            BuilderSystemInner::Initialized { system, .. } => unsafe {
388                system.run_unsafe(input, world)
389            },
390            BuilderSystemInner::Uninitialized { .. } => panic!(
391                "BuilderSystem {} was not initialized before calling run_unsafe.",
392                self.name()
393            ),
394            BuilderSystemInner::Invalid => unreachable!(),
395        }
396    }
397
398    #[cfg(feature = "hotpatching")]
399    #[inline]
400    fn refresh_hotpatch(&mut self) {
401        match &mut self.inner {
402            BuilderSystemInner::Initialized { system, .. } => system.refresh_hotpatch(),
403            BuilderSystemInner::Uninitialized { .. } => {}
404            BuilderSystemInner::Invalid => unreachable!(),
405        }
406    }
407
408    #[inline]
409    fn apply_deferred(&mut self, world: &mut World) {
410        match &mut self.inner {
411            BuilderSystemInner::Initialized { system, .. } => system.apply_deferred(world),
412            BuilderSystemInner::Uninitialized { .. } => {}
413            BuilderSystemInner::Invalid => unreachable!(),
414        }
415    }
416
417    #[inline]
418    fn queue_deferred(&mut self, world: DeferredWorld) {
419        match &mut self.inner {
420            BuilderSystemInner::Initialized { system, .. } => system.queue_deferred(world),
421            BuilderSystemInner::Uninitialized { .. } => {}
422            BuilderSystemInner::Invalid => unreachable!(),
423        }
424    }
425
426    #[inline]
427    fn initialize(&mut self, world: &mut World) -> FilteredAccessSet {
428        let inner = mem::replace(&mut self.inner, BuilderSystemInner::Invalid);
429        match inner {
430            BuilderSystemInner::Initialized { mut system } => {
431                let access = system.initialize(world);
432                self.inner = BuilderSystemInner::Initialized { system };
433                access
434            }
435            BuilderSystemInner::Uninitialized { builder, func, .. } => {
436                let mut system = builder.build_state(world).build_any_system(func);
437                let access = system.initialize(world);
438                self.inner = BuilderSystemInner::Initialized { system };
439                access
440            }
441            BuilderSystemInner::Invalid => unreachable!(),
442        }
443    }
444
445    #[inline]
446    fn check_change_tick(&mut self, check: CheckChangeTicks) {
447        match &mut self.inner {
448            BuilderSystemInner::Initialized { system, .. } => system.check_change_tick(check),
449            BuilderSystemInner::Uninitialized { .. } => {}
450            BuilderSystemInner::Invalid => unreachable!(),
451        }
452    }
453
454    #[inline]
455    fn get_last_run(&self) -> Tick {
456        match &self.inner {
457            BuilderSystemInner::Initialized { system, .. } => system.get_last_run(),
458            BuilderSystemInner::Uninitialized { meta, .. } => meta.get_last_run(),
459            BuilderSystemInner::Invalid => unreachable!(),
460        }
461    }
462
463    #[inline]
464    fn set_last_run(&mut self, last_run: Tick) {
465        match &mut self.inner {
466            BuilderSystemInner::Initialized { system, .. } => system.set_last_run(last_run),
467            BuilderSystemInner::Uninitialized { meta, .. } => meta.set_last_run(last_run),
468            BuilderSystemInner::Invalid => unreachable!(),
469        }
470    }
471}
472
473// SAFETY: if the wrapped system is read-only, so is this one
474unsafe impl<Marker, In, Out, Func, Builder> ReadOnlySystem
475    for BuilderSystem<Marker, In, Out, Func, Builder>
476where
477    Marker: 'static,
478    In: SystemInput + 'static,
479    Out: 'static,
480    Func: SystemParamFunction<Marker, In: FromInput<In>, Out: IntoResult<Out>>,
481    Builder: SystemParamBuilder<Func::Param> + Send + Sync + 'static,
482    // the important bound
483    FunctionSystem<Marker, In, Out, Func>: ReadOnlySystem,
484{
485}
486
487// SAFETY: Any `QueryState<D, F>` for the correct world is valid for `Query::State`,
488// and we check the world during `build`.
489unsafe impl<'w, 's, D: QueryData + 'static, F: QueryFilter + 'static>
490    SystemParamBuilder<Query<'w, 's, D, F>> for QueryState<D, F>
491{
492    fn build(self, world: &mut World) -> QueryState<D, F> {
493        self.validate_world(world.id());
494        self
495    }
496}
497
498/// A [`SystemParamBuilder`] for a [`Query`].
499/// This takes a closure accepting an `&mut` [`QueryBuilder`] and uses the builder to construct the query's state.
500/// This can be used to add additional filters,
501/// or to configure the components available to [`FilteredEntityRef`](crate::world::FilteredEntityRef) or [`FilteredEntityMut`](crate::world::FilteredEntityMut).
502///
503/// ## Example
504///
505/// ```
506/// # use bevy_ecs::{
507/// #     prelude::*,
508/// #     system::{SystemParam, QueryParamBuilder},
509/// # };
510/// #
511/// # #[derive(Component)]
512/// # struct Player;
513/// #
514/// # let mut world = World::new();
515/// let system = (QueryParamBuilder::new(|builder| {
516///     builder.with::<Player>();
517/// }),)
518///     .build_state(&mut world)
519///     .build_system(|query: Query<()>| {
520///         for _ in &query {
521///             // This only includes entities with a `Player` component.
522///         }
523///     });
524///
525/// // When collecting multiple builders into a `Vec`,
526/// // use `new_box()` to erase the closure type.
527/// let system = (vec![
528///     QueryParamBuilder::new_box(|builder| {
529///         builder.with::<Player>();
530///     }),
531///     QueryParamBuilder::new_box(|builder| {
532///         builder.without::<Player>();
533///     }),
534/// ],)
535///     .build_state(&mut world)
536///     .build_system(|query: Vec<Query<()>>| {});
537/// ```
538#[derive(Clone)]
539pub struct QueryParamBuilder<T>(T);
540
541impl<T> QueryParamBuilder<T> {
542    /// Creates a [`SystemParamBuilder`] for a [`Query`] that accepts a callback to configure the [`QueryBuilder`].
543    pub fn new<D: QueryData, F: QueryFilter>(f: T) -> Self
544    where
545        T: FnOnce(&mut QueryBuilder<D, F>),
546    {
547        Self(f)
548    }
549}
550
551impl<'a, D: QueryData, F: QueryFilter>
552    QueryParamBuilder<Box<dyn FnOnce(&mut QueryBuilder<D, F>) + 'a>>
553{
554    /// Creates a [`SystemParamBuilder`] for a [`Query`] that accepts a callback to configure the [`QueryBuilder`].
555    /// This boxes the callback so that it has a common type and can be put in a `Vec`.
556    pub fn new_box(f: impl FnOnce(&mut QueryBuilder<D, F>) + 'a) -> Self {
557        Self(Box::new(f))
558    }
559}
560
561// SAFETY: Any `QueryState<D, F>` for the correct world is valid for `Query::State`,
562// and `QueryBuilder` produces one with the given `world`.
563unsafe impl<
564        'w,
565        's,
566        D: QueryData + 'static,
567        F: QueryFilter + 'static,
568        T: FnOnce(&mut QueryBuilder<D, F>),
569    > SystemParamBuilder<Query<'w, 's, D, F>> for QueryParamBuilder<T>
570{
571    fn build(self, world: &mut World) -> QueryState<D, F> {
572        let mut builder = QueryBuilder::new(world);
573        (self.0)(&mut builder);
574        builder.build()
575    }
576}
577
578macro_rules! impl_system_param_builder_tuple {
579    ($(#[$meta:meta])* $(($param: ident, $builder: ident)),*) => {
580        #[expect(
581            clippy::allow_attributes,
582            reason = "This is in a macro; as such, the below lints may not always apply."
583        )]
584        #[allow(
585            unused_variables,
586            reason = "Zero-length tuples won't use any of the parameters."
587        )]
588        #[allow(
589            non_snake_case,
590            reason = "The variable names are provided by the macro caller, not by us."
591        )]
592        $(#[$meta])*
593        // SAFETY: implementors of each `SystemParamBuilder` in the tuple have validated their impls
594        unsafe impl<$($param: SystemParam,)* $($builder: SystemParamBuilder<$param>,)*> SystemParamBuilder<($($param,)*)> for ($($builder,)*) {
595            fn build(self, world: &mut World) -> <($($param,)*) as SystemParam>::State {
596                let ($($builder,)*) = self;
597                #[allow(
598                    clippy::unused_unit,
599                    reason = "Zero-length tuples won't generate any calls to the system parameter builders."
600                )]
601                ($($builder.build(world),)*)
602            }
603        }
604    };
605}
606
607all_tuples!(
608    #[doc(fake_variadic)]
609    impl_system_param_builder_tuple,
610    0,
611    16,
612    P,
613    B
614);
615
616// SAFETY: implementors of each `SystemParamBuilder` in the vec have validated their impls
617unsafe impl<P: SystemParam, B: SystemParamBuilder<P>> SystemParamBuilder<Vec<P>> for Vec<B> {
618    fn build(self, world: &mut World) -> <Vec<P> as SystemParam>::State {
619        self.into_iter()
620            .map(|builder| builder.build(world))
621            .collect()
622    }
623}
624
625// SAFETY: implementors of each `SystemParamBuilder` in the vec have validated their impls
626unsafe impl<P: SystemParam, B: SystemParamBuilder<P>, const N: usize>
627    SystemParamBuilder<SmallVec<[P; N]>> for SmallVec<[B; N]>
628{
629    fn build(self, world: &mut World) -> <SmallVec<[P; N]> as SystemParam>::State {
630        self.into_iter()
631            .map(|builder| builder.build(world))
632            .collect()
633    }
634}
635
636/// A [`SystemParamBuilder`] for a [`ParamSet`].
637///
638/// To build a [`ParamSet`] with a tuple of system parameters, pass a tuple of matching [`SystemParamBuilder`]s.
639/// To build a [`ParamSet`] with a [`Vec`] of system parameters, pass a `Vec` of matching [`SystemParamBuilder`]s.
640///
641/// # Examples
642///
643/// ```
644/// # use bevy_ecs::{prelude::*, system::*};
645/// #
646/// # #[derive(Component)]
647/// # struct Health;
648/// #
649/// # #[derive(Component)]
650/// # struct Enemy;
651/// #
652/// # #[derive(Component)]
653/// # struct Ally;
654/// #
655/// # let mut world = World::new();
656/// #
657/// let system = (ParamSetBuilder((
658///     QueryParamBuilder::new(|builder| {
659///         builder.with::<Enemy>();
660///     }),
661///     QueryParamBuilder::new(|builder| {
662///         builder.with::<Ally>();
663///     }),
664///     ParamBuilder,
665/// )),)
666///     .build_state(&mut world)
667///     .build_system(buildable_system_with_tuple);
668/// # world.run_system_once(system);
669///
670/// fn buildable_system_with_tuple(
671///     mut set: ParamSet<(Query<&mut Health>, Query<&mut Health>, &World)>,
672/// ) {
673///     // The first parameter is built from the first builder,
674///     // so this will iterate over enemies.
675///     for mut health in set.p0().iter_mut() {}
676///     // And the second parameter is built from the second builder,
677///     // so this will iterate over allies.
678///     for mut health in set.p1().iter_mut() {}
679///     // Parameters that don't need special building can use `ParamBuilder`.
680///     let entities = set.p2().entities();
681/// }
682///
683/// let system = (ParamSetBuilder(vec![
684///     QueryParamBuilder::new_box(|builder| {
685///         builder.with::<Enemy>();
686///     }),
687///     QueryParamBuilder::new_box(|builder| {
688///         builder.with::<Ally>();
689///     }),
690/// ]),)
691///     .build_state(&mut world)
692///     .build_system(buildable_system_with_vec);
693/// # world.run_system_once(system);
694///
695/// fn buildable_system_with_vec(mut set: ParamSet<Vec<Query<&mut Health>>>) {
696///     // As with tuples, the first parameter is built from the first builder,
697///     // so this will iterate over enemies.
698///     for mut health in set.get_mut(0).iter_mut() {}
699///     // And the second parameter is built from the second builder,
700///     // so this will iterate over allies.
701///     for mut health in set.get_mut(1).iter_mut() {}
702///     // You can iterate over the parameters either by index,
703///     // or using the `for_each` method.
704///     set.for_each(|mut query| for mut health in query.iter_mut() {});
705/// }
706/// ```
707#[derive(Debug, Default, Clone)]
708pub struct ParamSetBuilder<T>(pub T);
709
710macro_rules! impl_param_set_builder_tuple {
711    ($(($param: ident, $builder: ident)),*) => {
712        #[expect(
713            clippy::allow_attributes,
714            reason = "This is in a macro; as such, the below lints may not always apply."
715        )]
716        #[allow(
717            unused_variables,
718            reason = "Zero-length tuples won't use any of the parameters."
719        )]
720        #[allow(
721            non_snake_case,
722            reason = "The variable names are provided by the macro caller, not by us."
723        )]
724        // SAFETY: implementors of each `SystemParamBuilder` in the tuple have validated their impls
725        unsafe impl<'w, 's, $($param: SystemParam,)* $($builder: SystemParamBuilder<$param>,)*> SystemParamBuilder<ParamSet<'w, 's, ($($param,)*)>> for ParamSetBuilder<($($builder,)*)> {
726            fn build(self, world: &mut World) -> <($($param,)*) as SystemParam>::State {
727                let ParamSetBuilder(($($builder,)*)) = self;
728                ($($builder.build(world),)*)
729            }
730        }
731    };
732}
733
734all_tuples!(impl_param_set_builder_tuple, 1, 8, P, B);
735
736// SAFETY: implementors of each `SystemParamBuilder` in the vec have validated their impls
737unsafe impl<'w, 's, P: SystemParam, B: SystemParamBuilder<P>>
738    SystemParamBuilder<ParamSet<'w, 's, Vec<P>>> for ParamSetBuilder<Vec<B>>
739{
740    fn build(self, world: &mut World) -> <Vec<P> as SystemParam>::State {
741        self.0
742            .into_iter()
743            .map(|builder| builder.build(world))
744            .collect()
745    }
746}
747
748/// A [`SystemParamBuilder`] for a [`DynSystemParam`].
749/// See the [`DynSystemParam`] docs for examples.
750pub struct DynParamBuilder<'a>(Box<dyn FnOnce(&mut World) -> DynSystemParamState + 'a>);
751
752impl<'a> DynParamBuilder<'a> {
753    /// Creates a new [`DynParamBuilder`] by wrapping a [`SystemParamBuilder`] of any type.
754    /// The built [`DynSystemParam`] can be downcast to `T`.
755    pub fn new<T: SystemParam + 'static>(builder: impl SystemParamBuilder<T> + 'a) -> Self {
756        Self(Box::new(|world| {
757            DynSystemParamState::new::<T>(builder.build(world))
758        }))
759    }
760}
761
762// SAFETY: `DynSystemParam::get_param` will call `get_param` on the boxed `DynSystemParamState`,
763// and the boxed builder was a valid implementation of `SystemParamBuilder` for that type.
764// The resulting `DynSystemParam` can only perform access by downcasting to that param type.
765unsafe impl<'a, 'w, 's> SystemParamBuilder<DynSystemParam<'w, 's>> for DynParamBuilder<'a> {
766    fn build(self, world: &mut World) -> <DynSystemParam<'w, 's> as SystemParam>::State {
767        (self.0)(world)
768    }
769}
770
771/// A [`SystemParamBuilder`] for a [`Local`].
772/// The provided value will be used as the initial value of the `Local`.
773///
774/// ## Example
775///
776/// ```
777/// # use bevy_ecs::{
778/// #     prelude::*,
779/// #     system::{SystemParam, LocalBuilder, RunSystemOnce},
780/// # };
781/// #
782/// # let mut world = World::new();
783/// let system = (LocalBuilder(100),)
784///     .build_state(&mut world)
785///     .build_system(|local: Local<usize>| {
786///         assert_eq!(*local, 100);
787///     });
788/// # world.run_system_once(system);
789/// ```
790#[derive(Default, Debug, Clone)]
791pub struct LocalBuilder<T>(pub T);
792
793// SAFETY: Any value of `T` is a valid state for `Local`.
794unsafe impl<'s, T: FromWorld + Send + 'static> SystemParamBuilder<Local<'s, T>>
795    for LocalBuilder<T>
796{
797    fn build(self, _world: &mut World) -> <Local<'s, T> as SystemParam>::State {
798        SyncCell::new(self.0)
799    }
800}
801
802/// A [`SystemParamBuilder`] for a [`FilteredResources`].
803/// See the [`FilteredResources`] docs for examples.
804#[derive(Clone)]
805pub struct FilteredResourcesParamBuilder<T>(T);
806
807impl<T> FilteredResourcesParamBuilder<T> {
808    /// Creates a [`SystemParamBuilder`] for a [`FilteredResources`] that accepts a callback to configure the [`FilteredResourcesBuilder`].
809    pub fn new(f: T) -> Self
810    where
811        T: FnOnce(&mut FilteredResourcesBuilder),
812    {
813        Self(f)
814    }
815}
816
817impl<'a> FilteredResourcesParamBuilder<Box<dyn FnOnce(&mut FilteredResourcesBuilder) + 'a>> {
818    /// Creates a [`SystemParamBuilder`] for a [`FilteredResources`] that accepts a callback to configure the [`FilteredResourcesBuilder`].
819    /// This boxes the callback so that it has a common type.
820    pub fn new_box(f: impl FnOnce(&mut FilteredResourcesBuilder) + 'a) -> Self {
821        Self(Box::new(f))
822    }
823}
824
825// SAFETY: Any `Access` is a valid state for `FilteredResources`.
826unsafe impl<'w, 's, T: FnOnce(&mut FilteredResourcesBuilder)>
827    SystemParamBuilder<FilteredResources<'w, 's>> for FilteredResourcesParamBuilder<T>
828{
829    fn build(self, world: &mut World) -> <FilteredResources<'w, 's> as SystemParam>::State {
830        let mut builder = FilteredResourcesBuilder::new(world);
831        (self.0)(&mut builder);
832        builder.build()
833    }
834}
835
836/// A [`SystemParamBuilder`] for a [`FilteredResourcesMut`].
837/// See the [`FilteredResourcesMut`] docs for examples.
838#[derive(Clone)]
839pub struct FilteredResourcesMutParamBuilder<T>(T);
840
841impl<T> FilteredResourcesMutParamBuilder<T> {
842    /// Creates a [`SystemParamBuilder`] for a [`FilteredResourcesMut`] that accepts a callback to configure the [`FilteredResourcesMutBuilder`].
843    pub fn new(f: T) -> Self
844    where
845        T: FnOnce(&mut FilteredResourcesMutBuilder),
846    {
847        Self(f)
848    }
849}
850
851impl<'a> FilteredResourcesMutParamBuilder<Box<dyn FnOnce(&mut FilteredResourcesMutBuilder) + 'a>> {
852    /// Creates a [`SystemParamBuilder`] for a [`FilteredResourcesMut`] that accepts a callback to configure the [`FilteredResourcesMutBuilder`].
853    /// This boxes the callback so that it has a common type.
854    pub fn new_box(f: impl FnOnce(&mut FilteredResourcesMutBuilder) + 'a) -> Self {
855        Self(Box::new(f))
856    }
857}
858
859// SAFETY: Any `Access` is a valid state for `FilteredResourcesMut`.
860unsafe impl<'w, 's, T: FnOnce(&mut FilteredResourcesMutBuilder)>
861    SystemParamBuilder<FilteredResourcesMut<'w, 's>> for FilteredResourcesMutParamBuilder<T>
862{
863    fn build(self, world: &mut World) -> <FilteredResourcesMut<'w, 's> as SystemParam>::State {
864        let mut builder = FilteredResourcesMutBuilder::new(world);
865        (self.0)(&mut builder);
866        builder.build()
867    }
868}
869
870/// A [`SystemParamBuilder`] for an [`Option`].
871#[derive(Clone)]
872pub struct OptionBuilder<T>(T);
873
874// SAFETY: `OptionBuilder<B>` builds a state that is valid for `P`, and any state valid for `P` is valid for `Option<P>`
875unsafe impl<P: SystemParam, B: SystemParamBuilder<P>> SystemParamBuilder<Option<P>>
876    for OptionBuilder<B>
877{
878    fn build(self, world: &mut World) -> <Option<P> as SystemParam>::State {
879        self.0.build(world)
880    }
881}
882
883/// A [`SystemParamBuilder`] for a [`Result`] of [`SystemParamValidationError`].
884#[derive(Clone)]
885pub struct ResultBuilder<T>(T);
886
887// SAFETY: `ResultBuilder<B>` builds a state that is valid for `P`, and any state valid for `P` is valid for `Result<P, SystemParamValidationError>`
888unsafe impl<P: SystemParam, B: SystemParamBuilder<P>>
889    SystemParamBuilder<Result<P, SystemParamValidationError>> for ResultBuilder<B>
890{
891    fn build(
892        self,
893        world: &mut World,
894    ) -> <Result<P, SystemParamValidationError> as SystemParam>::State {
895        self.0.build(world)
896    }
897}
898
899/// A [`SystemParamBuilder`] for a [`If`].
900#[derive(Clone)]
901pub struct IfBuilder<T>(T);
902
903// SAFETY: `IfBuilder<B>` builds a state that is valid for `P`, and any state valid for `P` is valid for `If<P>`
904unsafe impl<P: SystemParam, B: SystemParamBuilder<P>> SystemParamBuilder<If<P>> for IfBuilder<B> {
905    fn build(self, world: &mut World) -> <If<P> as SystemParam>::State {
906        self.0.build(world)
907    }
908}
909
910#[cfg(test)]
911mod tests {
912    use crate::{
913        entity::Entities,
914        error::Result,
915        prelude::{Component, Query},
916        reflect::ReflectResource,
917        system::{Local, RunSystemOnce},
918    };
919    use alloc::vec;
920    use bevy_reflect::Reflect;
921
922    use super::*;
923
924    #[derive(Component)]
925    struct A;
926
927    #[derive(Component)]
928    struct B;
929
930    #[derive(Component)]
931    struct C;
932
933    #[derive(Resource, Default, Reflect)]
934    #[reflect(Resource)]
935    struct R {
936        foo: usize,
937    }
938
939    fn local_system(local: Local<u64>) -> u64 {
940        *local
941    }
942
943    fn query_system(query: Query<()>) -> usize {
944        query.iter().count()
945    }
946
947    fn query_system_result(query: Query<()>) -> Result<usize> {
948        Ok(query.iter().count())
949    }
950
951    fn multi_param_system(a: Local<u64>, b: Local<u64>) -> u64 {
952        *a + *b + 1
953    }
954
955    #[test]
956    fn local_builder() {
957        let mut world = World::new();
958
959        let system = (LocalBuilder(10),)
960            .build_state(&mut world)
961            .build_system(local_system);
962
963        let output = world.run_system_once(system).unwrap();
964        assert_eq!(output, 10);
965
966        let builder_system = (LocalBuilder(10),).build_system(local_system);
967
968        let output = world.run_system_once(builder_system).unwrap();
969        assert_eq!(output, 10);
970    }
971
972    #[test]
973    fn query_builder() {
974        let mut world = World::new();
975
976        world.spawn(A);
977        world.spawn_empty();
978
979        let system = (QueryParamBuilder::new(|query| {
980            query.with::<A>();
981        }),)
982            .build_state(&mut world)
983            .build_system(query_system);
984
985        let output = world.run_system_once(system).unwrap();
986        assert_eq!(output, 1);
987
988        let builder_system = (QueryParamBuilder::new(|query| {
989            query.with::<A>();
990        }),)
991            .build_system(query_system);
992
993        let output = world.run_system_once(builder_system).unwrap();
994        assert_eq!(output, 1);
995    }
996
997    #[test]
998    fn query_builder_system_result_fallible() {
999        let mut world = World::new();
1000
1001        world.spawn(A);
1002        world.spawn_empty();
1003
1004        let system = (QueryParamBuilder::new(|query| {
1005            query.with::<A>();
1006        }),)
1007            .build_state(&mut world)
1008            .build_system(query_system_result);
1009
1010        // The type annotation here is necessary since the system
1011        // could also return `Result<usize>`
1012        let output: usize = world.run_system_once(system).unwrap();
1013        assert_eq!(output, 1);
1014
1015        let builder_system = (QueryParamBuilder::new(|query| {
1016            query.with::<A>();
1017        }),)
1018            .build_system(query_system_result);
1019
1020        // The type annotation here is necessary since the system
1021        // could also return `Result<usize>`
1022        let output: usize = world.run_system_once(builder_system).unwrap();
1023        assert_eq!(output, 1);
1024    }
1025
1026    #[test]
1027    fn query_builder_result_infallible() {
1028        let mut world = World::new();
1029
1030        world.spawn(A);
1031        world.spawn_empty();
1032
1033        let system = (QueryParamBuilder::new(|query| {
1034            query.with::<A>();
1035        }),)
1036            .build_state(&mut world)
1037            .build_system(query_system_result);
1038
1039        // The type annotation here is necessary since the system
1040        // could also return `usize`
1041        let output: Result<usize> = world.run_system_once(system).unwrap();
1042        assert_eq!(output.unwrap(), 1);
1043
1044        let builder_system = (QueryParamBuilder::new(|query| {
1045            query.with::<A>();
1046        }),)
1047            .build_system(query_system_result);
1048
1049        // The type annotation here is necessary since the system
1050        // could also return `usize`
1051        let output: Result<usize> = world.run_system_once(builder_system).unwrap();
1052        assert_eq!(output.unwrap(), 1);
1053    }
1054
1055    #[test]
1056    fn query_builder_state() {
1057        let mut world = World::new();
1058
1059        world.spawn(A);
1060        world.spawn_empty();
1061
1062        let state = QueryBuilder::new(&mut world).with::<A>().build();
1063
1064        let system = (state,).build_state(&mut world).build_system(query_system);
1065
1066        let output = world.run_system_once(system).unwrap();
1067        assert_eq!(output, 1);
1068
1069        let state = QueryBuilder::new(&mut world).with::<A>().build();
1070
1071        let builder_system = (state,).build_system(query_system);
1072
1073        let output = world.run_system_once(builder_system).unwrap();
1074        assert_eq!(output, 1);
1075    }
1076
1077    #[test]
1078    fn multi_param_builder() {
1079        let mut world = World::new();
1080
1081        world.spawn(A);
1082        world.spawn_empty();
1083
1084        let system = (LocalBuilder(0), ParamBuilder)
1085            .build_state(&mut world)
1086            .build_system(multi_param_system);
1087
1088        let output = world.run_system_once(system).unwrap();
1089        assert_eq!(output, 1);
1090
1091        let builder_system = (LocalBuilder(0), ParamBuilder).build_system(multi_param_system);
1092
1093        let output = world.run_system_once(builder_system).unwrap();
1094        assert_eq!(output, 1);
1095    }
1096
1097    #[test]
1098    fn vec_builder() {
1099        let mut world = World::new();
1100
1101        world.spawn((A, B, C));
1102        world.spawn((A, B));
1103        world.spawn((A, C));
1104        world.spawn((A, C));
1105        world.spawn_empty();
1106
1107        let system = (vec![
1108            QueryParamBuilder::new_box(|builder| {
1109                builder.with::<B>().without::<C>();
1110            }),
1111            QueryParamBuilder::new_box(|builder| {
1112                builder.with::<C>().without::<B>();
1113            }),
1114        ],)
1115            .build_state(&mut world)
1116            .build_system(|params: Vec<Query<&mut A>>| {
1117                let mut count: usize = 0;
1118                params
1119                    .into_iter()
1120                    .for_each(|mut query| count += query.iter_mut().count());
1121                count
1122            });
1123
1124        // NOTE: this isn't compatible with `BuilderSystem`, because the system param builder isn't 'static
1125
1126        let output = world.run_system_once(system).unwrap();
1127        assert_eq!(output, 3);
1128    }
1129
1130    #[test]
1131    fn multi_param_builder_inference() {
1132        let mut world = World::new();
1133
1134        world.spawn(A);
1135        world.spawn_empty();
1136
1137        let system = (LocalBuilder(0u64), ParamBuilder::local::<u64>())
1138            .build_state(&mut world)
1139            .build_system(|a, b| *a + *b + 1);
1140
1141        // NOTE: this isn't compatible with `BuilderSystem`, because it uses parameter type inference
1142
1143        let output = world.run_system_once(system).unwrap();
1144        assert_eq!(output, 1);
1145    }
1146
1147    #[test]
1148    fn param_set_builder() {
1149        let mut world = World::new();
1150
1151        world.spawn((A, B, C));
1152        world.spawn((A, B));
1153        world.spawn((A, C));
1154        world.spawn((A, C));
1155        world.spawn_empty();
1156
1157        let system = (ParamSetBuilder((
1158            QueryParamBuilder::new(|builder| {
1159                builder.with::<B>();
1160            }),
1161            QueryParamBuilder::new(|builder| {
1162                builder.with::<C>();
1163            }),
1164        )),)
1165            .build_state(&mut world)
1166            .build_system(|mut params: ParamSet<(Query<&mut A>, Query<&mut A>)>| {
1167                params.p0().iter().count() + params.p1().iter().count()
1168            });
1169
1170        let output = world.run_system_once(system).unwrap();
1171        assert_eq!(output, 5);
1172
1173        let builder_system = (ParamSetBuilder((
1174            QueryParamBuilder::new(|builder| {
1175                builder.with::<B>();
1176            }),
1177            QueryParamBuilder::new(|builder| {
1178                builder.with::<C>();
1179            }),
1180        )),)
1181            .build_system(|mut params: ParamSet<(Query<&mut A>, Query<&mut A>)>| {
1182                params.p0().iter().count() + params.p1().iter().count()
1183            });
1184
1185        let output = world.run_system_once(builder_system).unwrap();
1186        assert_eq!(output, 5);
1187    }
1188
1189    #[test]
1190    fn param_set_vec_builder() {
1191        let mut world = World::new();
1192
1193        world.spawn((A, B, C));
1194        world.spawn((A, B));
1195        world.spawn((A, C));
1196        world.spawn((A, C));
1197        world.spawn_empty();
1198
1199        let system = (ParamSetBuilder(vec![
1200            QueryParamBuilder::new_box(|builder| {
1201                builder.with::<B>();
1202            }),
1203            QueryParamBuilder::new_box(|builder| {
1204                builder.with::<C>();
1205            }),
1206        ]),)
1207            .build_state(&mut world)
1208            .build_system(|mut params: ParamSet<Vec<Query<&mut A>>>| {
1209                let mut count = 0;
1210                params.for_each(|mut query| count += query.iter_mut().count());
1211                count
1212            });
1213
1214        // NOTE: this isn't compatible with `BuilderSystem`, because the system param builder isn't 'static
1215
1216        let output = world.run_system_once(system).unwrap();
1217        assert_eq!(output, 5);
1218    }
1219
1220    #[test]
1221    fn dyn_builder() {
1222        let mut world = World::new();
1223
1224        world.spawn(A);
1225        world.spawn_empty();
1226
1227        let system = (
1228            DynParamBuilder::new(LocalBuilder(3_usize)),
1229            DynParamBuilder::new::<Query<()>>(QueryParamBuilder::new(|builder| {
1230                builder.with::<A>();
1231            })),
1232            DynParamBuilder::new::<&Entities>(ParamBuilder),
1233        )
1234            .build_state(&mut world)
1235            .build_system(
1236                |mut p0: DynSystemParam, mut p1: DynSystemParam, mut p2: DynSystemParam| {
1237                    let local = *p0.downcast_mut::<Local<usize>>().unwrap();
1238                    let query_count = p1.downcast_mut::<Query<()>>().unwrap().iter().count();
1239                    let _entities = p2.downcast_mut::<&Entities>().unwrap();
1240                    assert!(p0.downcast_mut::<Query<()>>().is_none());
1241                    local + query_count
1242                },
1243            );
1244
1245        // NOTE: this isn't compatible with `BuilderSystem`, because the system param builder isn't 'static
1246
1247        let output = world.run_system_once(system).unwrap();
1248        assert_eq!(output, 4);
1249    }
1250
1251    #[derive(SystemParam)]
1252    #[system_param(builder)]
1253    struct CustomParam<'w, 's> {
1254        query: Query<'w, 's, ()>,
1255        local: Local<'s, usize>,
1256    }
1257
1258    #[test]
1259    fn custom_param_builder() {
1260        let mut world = World::new();
1261
1262        world.spawn(A);
1263        world.spawn_empty();
1264
1265        let system = (CustomParamBuilder {
1266            local: LocalBuilder(100),
1267            query: QueryParamBuilder::new(|builder| {
1268                builder.with::<A>();
1269            }),
1270        },)
1271            .build_state(&mut world)
1272            .build_system(|param: CustomParam| *param.local + param.query.iter().count());
1273
1274        let output = world.run_system_once(system).unwrap();
1275        assert_eq!(output, 101);
1276
1277        let builder_system = (CustomParamBuilder {
1278            local: LocalBuilder(100),
1279            query: QueryParamBuilder::new(|builder| {
1280                builder.with::<A>();
1281            }),
1282        },)
1283            .build_system(|param: CustomParam| *param.local + param.query.iter().count());
1284
1285        let output = world.run_system_once(builder_system).unwrap();
1286        assert_eq!(output, 101);
1287    }
1288
1289    #[test]
1290    fn filtered_resource_conflicts_read_with_res() {
1291        let mut world = World::new();
1292        (
1293            ParamBuilder::resource(),
1294            FilteredResourcesParamBuilder::new(|builder| {
1295                builder.add_read::<R>();
1296            }),
1297        )
1298            .build_state(&mut world)
1299            .build_system(|_r: Res<R>, _fr: FilteredResources| {});
1300    }
1301
1302    #[test]
1303    #[should_panic]
1304    fn filtered_resource_conflicts_read_with_resmut() {
1305        let mut world = World::new();
1306        (
1307            ParamBuilder::resource_mut(),
1308            FilteredResourcesParamBuilder::new(|builder| {
1309                builder.add_read::<R>();
1310            }),
1311        )
1312            .build_state(&mut world)
1313            .build_system(|_r: ResMut<R>, _fr: FilteredResources| {});
1314    }
1315
1316    #[test]
1317    #[should_panic]
1318    fn filtered_resource_conflicts_read_all_with_resmut() {
1319        let mut world = World::new();
1320        (
1321            ParamBuilder::resource_mut(),
1322            FilteredResourcesParamBuilder::new(|builder| {
1323                builder.add_read_all();
1324            }),
1325        )
1326            .build_state(&mut world)
1327            .build_system(|_r: ResMut<R>, _fr: FilteredResources| {});
1328    }
1329
1330    #[test]
1331    fn filtered_resource_mut_conflicts_read_with_res() {
1332        let mut world = World::new();
1333        (
1334            ParamBuilder::resource(),
1335            FilteredResourcesMutParamBuilder::new(|builder| {
1336                builder.add_read::<R>();
1337            }),
1338        )
1339            .build_state(&mut world)
1340            .build_system(|_r: Res<R>, _fr: FilteredResourcesMut| {});
1341    }
1342
1343    #[test]
1344    #[should_panic]
1345    fn filtered_resource_mut_conflicts_read_with_resmut() {
1346        let mut world = World::new();
1347        (
1348            ParamBuilder::resource_mut(),
1349            FilteredResourcesMutParamBuilder::new(|builder| {
1350                builder.add_read::<R>();
1351            }),
1352        )
1353            .build_state(&mut world)
1354            .build_system(|_r: ResMut<R>, _fr: FilteredResourcesMut| {});
1355    }
1356
1357    #[test]
1358    #[should_panic]
1359    fn filtered_resource_mut_conflicts_write_with_res() {
1360        let mut world = World::new();
1361        (
1362            ParamBuilder::resource(),
1363            FilteredResourcesMutParamBuilder::new(|builder| {
1364                builder.add_write::<R>();
1365            }),
1366        )
1367            .build_state(&mut world)
1368            .build_system(|_r: Res<R>, _fr: FilteredResourcesMut| {});
1369    }
1370
1371    #[test]
1372    #[should_panic]
1373    fn filtered_resource_mut_conflicts_write_all_with_res() {
1374        let mut world = World::new();
1375        (
1376            ParamBuilder::resource(),
1377            FilteredResourcesMutParamBuilder::new(|builder| {
1378                builder.add_write_all();
1379            }),
1380        )
1381            .build_state(&mut world)
1382            .build_system(|_r: Res<R>, _fr: FilteredResourcesMut| {});
1383    }
1384
1385    #[test]
1386    #[should_panic]
1387    fn filtered_resource_mut_conflicts_write_with_resmut() {
1388        let mut world = World::new();
1389        (
1390            ParamBuilder::resource_mut(),
1391            FilteredResourcesMutParamBuilder::new(|builder| {
1392                builder.add_write::<R>();
1393            }),
1394        )
1395            .build_state(&mut world)
1396            .build_system(|_r: ResMut<R>, _fr: FilteredResourcesMut| {});
1397    }
1398}