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::{QueryData, QueryFilter, QueryState},
12 resource::Resource,
13 system::{
14 DynSystemParam, DynSystemParamState, FromInput, FunctionSystem, If, IntoResult, IntoSystem,
15 Local, ParamSet, Query, ReadOnlySystem, System, SystemAccess, SystemInput, SystemMeta,
16 SystemParam, SystemParamFunction, SystemParamValidationError,
17 },
18 world::{unsafe_world_cell::UnsafeWorldCell, DeferredWorld, FromWorld, World},
19};
20
21#[expect(deprecated, reason = "`FilteredResources` will be removed.")]
22use crate::world::{
23 FilteredResources, FilteredResourcesBuilder, FilteredResourcesMut, FilteredResourcesMutBuilder,
24};
25
26use core::{fmt::Debug, marker::PhantomData, mem};
27
28use super::{Res, ResMut, RunSystemError, SystemState, SystemStateFlags};
29
30pub unsafe trait SystemParamBuilder<P: SystemParam>: Sized {
135 fn build(self, world: &mut World) -> P::State;
138
139 fn build_state(self, world: &mut World) -> SystemState<P> {
142 SystemState::from_builder(world, self)
143 }
144
145 fn build_system<Marker, In, Out, Func>(
161 self,
162 func: Func,
163 ) -> IntoBuilderSystem<Marker, In, Out, Func, Self>
164 where
165 Self: 'static,
166 Func: SystemParamFunction<Marker, Param = P>,
167 {
168 IntoBuilderSystem::new(self, func)
169 }
170}
171
172#[derive(Default, Debug, Clone)]
212pub struct ParamBuilder;
213
214unsafe impl<P: SystemParam> SystemParamBuilder<P> for ParamBuilder {
216 fn build(self, world: &mut World) -> P::State {
217 P::init_state(world)
218 }
219}
220
221impl ParamBuilder {
222 pub fn of<T: SystemParam>() -> impl SystemParamBuilder<T> {
224 Self
225 }
226
227 pub fn resource<'w, T: Resource>() -> impl SystemParamBuilder<Res<'w, T>> {
229 Self
230 }
231
232 pub fn resource_mut<'w, T: Resource<Mutability = Mutable>>(
234 ) -> impl SystemParamBuilder<ResMut<'w, T>> {
235 Self
236 }
237
238 pub fn local<'s, T: FromWorld + Send + 'static>() -> impl SystemParamBuilder<Local<'s, T>> {
240 Self
241 }
242
243 pub fn query<'w, 's, D: QueryData + 'static>() -> impl SystemParamBuilder<Query<'w, 's, D, ()>>
245 {
246 Self
247 }
248
249 pub fn query_filtered<'w, 's, D: QueryData + 'static, F: QueryFilter + 'static>(
251 ) -> impl SystemParamBuilder<Query<'w, 's, D, F>> {
252 Self
253 }
254}
255
256#[doc(hidden)]
258pub struct IsBuilderSystem;
259
260pub struct IntoBuilderSystem<Marker, In, Out, Func, Builder>
262where
263 Func: SystemParamFunction<Marker>,
264 Builder: SystemParamBuilder<Func::Param>,
265{
266 builder: Builder,
267 func: Func,
268 _marker: PhantomData<fn(In) -> (Marker, Out)>,
269}
270
271impl<Marker, In, Out, Func, Builder> IntoBuilderSystem<Marker, In, Out, Func, Builder>
272where
273 Func: SystemParamFunction<Marker>,
274 Builder: SystemParamBuilder<Func::Param>,
275{
276 pub fn new(builder: Builder, func: Func) -> Self {
278 Self {
279 builder,
280 func,
281 _marker: PhantomData,
282 }
283 }
284}
285
286impl<Marker, In, Out, Func, Builder> IntoSystem<In, Out, (IsBuilderSystem, Marker)>
287 for IntoBuilderSystem<Marker, In, Out, Func, Builder>
288where
289 Marker: 'static,
290 In: SystemInput + 'static,
291 Out: 'static,
292 Func: SystemParamFunction<Marker, In: FromInput<In>, Out: IntoResult<Out>>,
293 Builder: SystemParamBuilder<Func::Param> + Send + Sync + 'static,
294{
295 type System = BuilderSystem<Marker, In, Out, Func, Builder>;
296
297 fn into_system(this: Self) -> Self::System {
298 BuilderSystem::new(this.builder, this.func)
299 }
300}
301
302pub struct BuilderSystem<Marker, In, Out, Func, Builder>
305where
306 Func: SystemParamFunction<Marker>,
307 Builder: SystemParamBuilder<Func::Param>,
308{
309 inner: BuilderSystemInner<Marker, In, Out, Func, Builder>,
310}
311
312impl<Marker, In, Out, Func, Builder> BuilderSystem<Marker, In, Out, Func, Builder>
313where
314 Func: SystemParamFunction<Marker>,
315 Builder: SystemParamBuilder<Func::Param>,
316{
317 pub fn new(builder: Builder, func: Func) -> Self {
319 Self {
320 inner: BuilderSystemInner::Uninitialized {
321 builder,
322 func,
323 meta: SystemMeta::new::<Func>(),
324 },
325 }
326 }
327}
328
329enum BuilderSystemInner<Marker, In, Out, Func, Builder>
330where
331 Func: SystemParamFunction<Marker>,
332 Builder: SystemParamBuilder<Func::Param>,
333{
334 Initialized {
336 system: FunctionSystem<Marker, In, Out, Func>,
337 },
338 Uninitialized {
341 builder: Builder,
342 func: Func,
343 meta: SystemMeta,
344 },
345 Invalid,
349}
350
351impl<Marker, In, Out, Func, Builder> System for BuilderSystem<Marker, In, Out, Func, Builder>
352where
353 Marker: 'static,
354 In: SystemInput + 'static,
355 Out: 'static,
356 Func: SystemParamFunction<Marker, In: FromInput<In>, Out: IntoResult<Out>>,
357 Builder: SystemParamBuilder<Func::Param> + Send + Sync + 'static,
358{
359 type In = In;
360
361 type Out = Out;
362
363 #[inline]
364 fn name(&self) -> DebugName {
365 match &self.inner {
366 BuilderSystemInner::Initialized { system } => system.name(),
367 BuilderSystemInner::Uninitialized { meta, .. } => meta.name().clone(),
368 BuilderSystemInner::Invalid => unreachable!(),
369 }
370 }
371
372 #[inline]
373 fn flags(&self) -> SystemStateFlags {
374 match &self.inner {
375 BuilderSystemInner::Initialized { system, .. } => system.flags(),
376 BuilderSystemInner::Uninitialized { meta, .. } => meta.flags(),
377 BuilderSystemInner::Invalid => unreachable!(),
378 }
379 }
380
381 #[inline]
382 unsafe fn run_unsafe(
383 &mut self,
384 input: super::SystemIn<'_, Self>,
385 world: UnsafeWorldCell,
386 ) -> Result<Self::Out, RunSystemError> {
387 match &mut self.inner {
388 BuilderSystemInner::Initialized { system, .. } => unsafe {
390 system.run_unsafe(input, world)
391 },
392 BuilderSystemInner::Uninitialized { .. } => panic!(
393 "BuilderSystem {} was not initialized before calling run_unsafe.",
394 self.name()
395 ),
396 BuilderSystemInner::Invalid => unreachable!(),
397 }
398 }
399
400 #[cfg(feature = "hotpatching")]
401 #[inline]
402 fn refresh_hotpatch(&mut self) {
403 match &mut self.inner {
404 BuilderSystemInner::Initialized { system, .. } => system.refresh_hotpatch(),
405 BuilderSystemInner::Uninitialized { .. } => {}
406 BuilderSystemInner::Invalid => unreachable!(),
407 }
408 }
409
410 #[inline]
411 fn apply_deferred(&mut self, world: &mut World) {
412 match &mut self.inner {
413 BuilderSystemInner::Initialized { system, .. } => system.apply_deferred(world),
414 BuilderSystemInner::Uninitialized { .. } => {}
415 BuilderSystemInner::Invalid => unreachable!(),
416 }
417 }
418
419 #[inline]
420 fn queue_deferred(&mut self, world: DeferredWorld) {
421 match &mut self.inner {
422 BuilderSystemInner::Initialized { system, .. } => system.queue_deferred(world),
423 BuilderSystemInner::Uninitialized { .. } => {}
424 BuilderSystemInner::Invalid => unreachable!(),
425 }
426 }
427
428 #[inline]
429 fn initialize(&mut self, world: &mut World) -> SystemAccess {
430 let inner = mem::replace(&mut self.inner, BuilderSystemInner::Invalid);
431 match inner {
432 BuilderSystemInner::Initialized { mut system } => {
433 let access = system.initialize(world);
434 self.inner = BuilderSystemInner::Initialized { system };
435 access
436 }
437 BuilderSystemInner::Uninitialized { builder, func, .. } => {
438 let mut system = builder.build_state(world).build_any_system(func);
439 let access = system.initialize(world);
440 self.inner = BuilderSystemInner::Initialized { system };
441 access
442 }
443 BuilderSystemInner::Invalid => unreachable!(),
444 }
445 }
446
447 #[inline]
448 fn check_change_tick(&mut self, check: CheckChangeTicks) {
449 match &mut self.inner {
450 BuilderSystemInner::Initialized { system, .. } => system.check_change_tick(check),
451 BuilderSystemInner::Uninitialized { .. } => {}
452 BuilderSystemInner::Invalid => unreachable!(),
453 }
454 }
455
456 #[inline]
457 fn get_last_run(&self) -> Tick {
458 match &self.inner {
459 BuilderSystemInner::Initialized { system, .. } => system.get_last_run(),
460 BuilderSystemInner::Uninitialized { meta, .. } => meta.get_last_run(),
461 BuilderSystemInner::Invalid => unreachable!(),
462 }
463 }
464
465 #[inline]
466 fn set_last_run(&mut self, last_run: Tick) {
467 match &mut self.inner {
468 BuilderSystemInner::Initialized { system, .. } => system.set_last_run(last_run),
469 BuilderSystemInner::Uninitialized { meta, .. } => meta.set_last_run(last_run),
470 BuilderSystemInner::Invalid => unreachable!(),
471 }
472 }
473}
474
475unsafe impl<Marker, In, Out, Func, Builder> ReadOnlySystem
477 for BuilderSystem<Marker, In, Out, Func, Builder>
478where
479 Marker: 'static,
480 In: SystemInput + 'static,
481 Out: 'static,
482 Func: SystemParamFunction<Marker, In: FromInput<In>, Out: IntoResult<Out>>,
483 Builder: SystemParamBuilder<Func::Param> + Send + Sync + 'static,
484 FunctionSystem<Marker, In, Out, Func>: ReadOnlySystem,
486{
487}
488
489unsafe impl<'w, 's, D: QueryData + 'static, F: QueryFilter + 'static>
492 SystemParamBuilder<Query<'w, 's, D, F>> for QueryState<D, F>
493{
494 fn build(self, world: &mut World) -> QueryState<D, F> {
495 self.validate_world(world.id());
496 self
497 }
498}
499
500#[derive(Clone)]
541pub struct QueryParamBuilder<T>(T);
542
543impl<T> QueryParamBuilder<T> {
544 pub fn new<D: QueryData, F: QueryFilter>(f: T) -> Self
546 where
547 T: FnOnce(&mut QueryBuilder<D, F>),
548 {
549 Self(f)
550 }
551}
552
553impl<'a, D: QueryData, F: QueryFilter>
554 QueryParamBuilder<Box<dyn FnOnce(&mut QueryBuilder<D, F>) + 'a>>
555{
556 pub fn new_box(f: impl FnOnce(&mut QueryBuilder<D, F>) + 'a) -> Self {
559 Self(Box::new(f))
560 }
561}
562
563unsafe impl<
566 'w,
567 's,
568 D: QueryData + 'static,
569 F: QueryFilter + 'static,
570 T: FnOnce(&mut QueryBuilder<D, F>),
571 > SystemParamBuilder<Query<'w, 's, D, F>> for QueryParamBuilder<T>
572{
573 fn build(self, world: &mut World) -> QueryState<D, F> {
574 let mut builder = QueryBuilder::new(world);
575 (self.0)(&mut builder);
576 builder.build()
577 }
578}
579
580macro_rules! impl_system_param_builder_tuple {
581 ($(#[$meta:meta])* $(($param: ident, $builder: ident)),*) => {
582 #[expect(
583 clippy::allow_attributes,
584 reason = "This is in a macro; as such, the below lints may not always apply."
585 )]
586 #[allow(
587 unused_variables,
588 reason = "Zero-length tuples won't use any of the parameters."
589 )]
590 #[allow(
591 non_snake_case,
592 reason = "The variable names are provided by the macro caller, not by us."
593 )]
594 $(#[$meta])*
595 unsafe impl<$($param: SystemParam,)* $($builder: SystemParamBuilder<$param>,)*> SystemParamBuilder<($($param,)*)> for ($($builder,)*) {
597 fn build(self, world: &mut World) -> <($($param,)*) as SystemParam>::State {
598 let ($($builder,)*) = self;
599 #[allow(
600 clippy::unused_unit,
601 reason = "Zero-length tuples won't generate any calls to the system parameter builders."
602 )]
603 ($($builder.build(world),)*)
604 }
605 }
606 };
607}
608
609all_tuples!(
610 #[doc(fake_variadic)]
611 impl_system_param_builder_tuple,
612 0,
613 16,
614 P,
615 B
616);
617
618unsafe impl<P: SystemParam, B: SystemParamBuilder<P>> SystemParamBuilder<Vec<P>> for Vec<B> {
620 fn build(self, world: &mut World) -> <Vec<P> as SystemParam>::State {
621 self.into_iter()
622 .map(|builder| builder.build(world))
623 .collect()
624 }
625}
626
627unsafe impl<P: SystemParam, B: SystemParamBuilder<P>, const N: usize>
629 SystemParamBuilder<SmallVec<[P; N]>> for SmallVec<[B; N]>
630{
631 fn build(self, world: &mut World) -> <SmallVec<[P; N]> as SystemParam>::State {
632 self.into_iter()
633 .map(|builder| builder.build(world))
634 .collect()
635 }
636}
637
638#[derive(Debug, Default, Clone)]
710pub struct ParamSetBuilder<T>(pub T);
711
712macro_rules! impl_param_set_builder_tuple {
713 ($(($param: ident, $builder: ident)),*) => {
714 #[expect(
715 clippy::allow_attributes,
716 reason = "This is in a macro; as such, the below lints may not always apply."
717 )]
718 #[allow(
719 unused_variables,
720 reason = "Zero-length tuples won't use any of the parameters."
721 )]
722 #[allow(
723 non_snake_case,
724 reason = "The variable names are provided by the macro caller, not by us."
725 )]
726 unsafe impl<'w, 's, $($param: SystemParam,)* $($builder: SystemParamBuilder<$param>,)*> SystemParamBuilder<ParamSet<'w, 's, ($($param,)*)>> for ParamSetBuilder<($($builder,)*)> {
728 fn build(self, world: &mut World) -> <($($param,)*) as SystemParam>::State {
729 let ParamSetBuilder(($($builder,)*)) = self;
730 ($($builder.build(world),)*)
731 }
732 }
733 };
734}
735
736all_tuples!(impl_param_set_builder_tuple, 1, 8, P, B);
737
738unsafe impl<'w, 's, P: SystemParam, B: SystemParamBuilder<P>>
740 SystemParamBuilder<ParamSet<'w, 's, Vec<P>>> for ParamSetBuilder<Vec<B>>
741{
742 fn build(self, world: &mut World) -> <Vec<P> as SystemParam>::State {
743 self.0
744 .into_iter()
745 .map(|builder| builder.build(world))
746 .collect()
747 }
748}
749
750pub struct DynParamBuilder<'a>(Box<dyn FnOnce(&mut World) -> DynSystemParamState + 'a>);
753
754impl<'a> DynParamBuilder<'a> {
755 pub fn new<T: SystemParam + 'static>(builder: impl SystemParamBuilder<T> + 'a) -> Self {
758 Self(Box::new(|world| {
759 DynSystemParamState::new::<T>(builder.build(world))
760 }))
761 }
762}
763
764unsafe impl<'a, 'w, 's> SystemParamBuilder<DynSystemParam<'w, 's>> for DynParamBuilder<'a> {
768 fn build(self, world: &mut World) -> <DynSystemParam<'w, 's> as SystemParam>::State {
769 (self.0)(world)
770 }
771}
772
773#[derive(Default, Debug, Clone)]
793pub struct LocalBuilder<T>(pub T);
794
795unsafe impl<'s, T: FromWorld + Send + 'static> SystemParamBuilder<Local<'s, T>>
797 for LocalBuilder<T>
798{
799 fn build(self, _world: &mut World) -> <Local<'s, T> as SystemParam>::State {
800 SyncCell::new(self.0)
801 }
802}
803
804#[derive(Clone)]
807#[deprecated(since = "0.20.0", note = "Use `QueryParamBuilder` instead.")]
808pub struct FilteredResourcesParamBuilder<T>(T);
809
810#[expect(
811 deprecated,
812 reason = "`FilteredResourcesParamBuilder` will be removed."
813)]
814impl<T> FilteredResourcesParamBuilder<T> {
815 pub fn new(f: T) -> Self
817 where
818 T: FnOnce(&mut FilteredResourcesBuilder),
819 {
820 Self(f)
821 }
822}
823
824#[expect(
825 deprecated,
826 reason = "`FilteredResourcesParamBuilder` will be removed."
827)]
828impl<'a> FilteredResourcesParamBuilder<Box<dyn FnOnce(&mut FilteredResourcesBuilder) + 'a>> {
829 pub fn new_box(f: impl FnOnce(&mut FilteredResourcesBuilder) + 'a) -> Self {
832 Self(Box::new(f))
833 }
834}
835
836#[expect(
837 deprecated,
838 reason = "`FilteredResourcesParamBuilder` will be removed."
839)]
840unsafe impl<'w, 's, T: FnOnce(&mut FilteredResourcesBuilder)>
842 SystemParamBuilder<FilteredResources<'w, 's>> for FilteredResourcesParamBuilder<T>
843{
844 fn build(self, world: &mut World) -> <FilteredResources<'w, 's> as SystemParam>::State {
845 let mut builder = FilteredResourcesBuilder::new(world);
846 (self.0)(&mut builder);
847 builder.build()
848 }
849}
850
851#[derive(Clone)]
854#[deprecated(since = "0.20.0", note = "Use `QueryParamBuilder` instead.")]
855pub struct FilteredResourcesMutParamBuilder<T>(T);
856
857#[expect(
858 deprecated,
859 reason = "`FilteredResourcesMutParamBuilder` will be removed."
860)]
861impl<T> FilteredResourcesMutParamBuilder<T> {
862 pub fn new(f: T) -> Self
864 where
865 T: FnOnce(&mut FilteredResourcesMutBuilder),
866 {
867 Self(f)
868 }
869}
870
871#[expect(
872 deprecated,
873 reason = "`FilteredResourcesMutParamBuilder` will be removed."
874)]
875impl<'a> FilteredResourcesMutParamBuilder<Box<dyn FnOnce(&mut FilteredResourcesMutBuilder) + 'a>> {
876 pub fn new_box(f: impl FnOnce(&mut FilteredResourcesMutBuilder) + 'a) -> Self {
879 Self(Box::new(f))
880 }
881}
882
883#[expect(
884 deprecated,
885 reason = "`FilteredResourcesMutParamBuilder` will be removed."
886)]
887unsafe impl<'w, 's, T: FnOnce(&mut FilteredResourcesMutBuilder)>
889 SystemParamBuilder<FilteredResourcesMut<'w, 's>> for FilteredResourcesMutParamBuilder<T>
890{
891 fn build(self, world: &mut World) -> <FilteredResourcesMut<'w, 's> as SystemParam>::State {
892 let mut builder = FilteredResourcesMutBuilder::new(world);
893 (self.0)(&mut builder);
894 builder.build()
895 }
896}
897
898#[derive(Clone)]
900pub struct OptionBuilder<T>(T);
901
902unsafe impl<P: SystemParam, B: SystemParamBuilder<P>> SystemParamBuilder<Option<P>>
904 for OptionBuilder<B>
905{
906 fn build(self, world: &mut World) -> <Option<P> as SystemParam>::State {
907 self.0.build(world)
908 }
909}
910
911#[derive(Clone)]
913pub struct ResultBuilder<T>(T);
914
915unsafe impl<P: SystemParam, B: SystemParamBuilder<P>>
917 SystemParamBuilder<Result<P, SystemParamValidationError>> for ResultBuilder<B>
918{
919 fn build(
920 self,
921 world: &mut World,
922 ) -> <Result<P, SystemParamValidationError> as SystemParam>::State {
923 self.0.build(world)
924 }
925}
926
927#[derive(Clone)]
929pub struct IfBuilder<T>(T);
930
931unsafe impl<P: SystemParam, B: SystemParamBuilder<P>> SystemParamBuilder<If<P>> for IfBuilder<B> {
933 fn build(self, world: &mut World) -> <If<P> as SystemParam>::State {
934 self.0.build(world)
935 }
936}
937
938#[cfg(test)]
939mod tests {
940 use crate::{
941 entity::Entities,
942 error::Result,
943 prelude::{Component, Query},
944 reflect::ReflectResource,
945 system::{Local, RunSystemOnce},
946 };
947 use alloc::vec;
948 use bevy_reflect::Reflect;
949
950 use super::*;
951
952 #[derive(Component)]
953 struct A;
954
955 #[derive(Component)]
956 struct B;
957
958 #[derive(Component)]
959 struct C;
960
961 #[derive(Resource, Default, Reflect)]
962 #[reflect(Resource)]
963 struct R {
964 foo: usize,
965 }
966
967 fn local_system(local: Local<u64>) -> u64 {
968 *local
969 }
970
971 fn query_system(query: Query<()>) -> usize {
972 query.iter().count()
973 }
974
975 fn query_system_result(query: Query<()>) -> Result<usize> {
976 Ok(query.iter().count())
977 }
978
979 fn multi_param_system(a: Local<u64>, b: Local<u64>) -> u64 {
980 *a + *b + 1
981 }
982
983 #[test]
984 fn local_builder() {
985 let mut world = World::new();
986
987 let system = (LocalBuilder(10),)
988 .build_state(&mut world)
989 .build_system(local_system);
990
991 let output = world.run_system_once(system).unwrap();
992 assert_eq!(output, 10);
993
994 let builder_system = (LocalBuilder(10),).build_system(local_system);
995
996 let output = world.run_system_once(builder_system).unwrap();
997 assert_eq!(output, 10);
998 }
999
1000 #[test]
1001 fn query_builder() {
1002 let mut world = World::new();
1003
1004 world.spawn(A);
1005 world.spawn_empty();
1006
1007 let system = (QueryParamBuilder::new(|query| {
1008 query.with::<A>();
1009 }),)
1010 .build_state(&mut world)
1011 .build_system(query_system);
1012
1013 let output = world.run_system_once(system).unwrap();
1014 assert_eq!(output, 1);
1015
1016 let builder_system = (QueryParamBuilder::new(|query| {
1017 query.with::<A>();
1018 }),)
1019 .build_system(query_system);
1020
1021 let output = world.run_system_once(builder_system).unwrap();
1022 assert_eq!(output, 1);
1023 }
1024
1025 #[test]
1026 fn query_builder_system_result_fallible() {
1027 let mut world = World::new();
1028
1029 world.spawn(A);
1030 world.spawn_empty();
1031
1032 let system = (QueryParamBuilder::new(|query| {
1033 query.with::<A>();
1034 }),)
1035 .build_state(&mut world)
1036 .build_system(query_system_result);
1037
1038 let output: usize = world.run_system_once(system).unwrap();
1041 assert_eq!(output, 1);
1042
1043 let builder_system = (QueryParamBuilder::new(|query| {
1044 query.with::<A>();
1045 }),)
1046 .build_system(query_system_result);
1047
1048 let output: usize = world.run_system_once(builder_system).unwrap();
1051 assert_eq!(output, 1);
1052 }
1053
1054 #[test]
1055 fn query_builder_result_infallible() {
1056 let mut world = World::new();
1057
1058 world.spawn(A);
1059 world.spawn_empty();
1060
1061 let system = (QueryParamBuilder::new(|query| {
1062 query.with::<A>();
1063 }),)
1064 .build_state(&mut world)
1065 .build_system(query_system_result);
1066
1067 let output: Result<usize> = world.run_system_once(system).unwrap();
1070 assert_eq!(output.unwrap(), 1);
1071
1072 let builder_system = (QueryParamBuilder::new(|query| {
1073 query.with::<A>();
1074 }),)
1075 .build_system(query_system_result);
1076
1077 let output: Result<usize> = world.run_system_once(builder_system).unwrap();
1080 assert_eq!(output.unwrap(), 1);
1081 }
1082
1083 #[test]
1084 fn query_builder_state() {
1085 let mut world = World::new();
1086
1087 world.spawn(A);
1088 world.spawn_empty();
1089
1090 let state = QueryBuilder::new(&mut world).with::<A>().build();
1091
1092 let system = (state,).build_state(&mut world).build_system(query_system);
1093
1094 let output = world.run_system_once(system).unwrap();
1095 assert_eq!(output, 1);
1096
1097 let state = QueryBuilder::new(&mut world).with::<A>().build();
1098
1099 let builder_system = (state,).build_system(query_system);
1100
1101 let output = world.run_system_once(builder_system).unwrap();
1102 assert_eq!(output, 1);
1103 }
1104
1105 #[test]
1106 fn multi_param_builder() {
1107 let mut world = World::new();
1108
1109 world.spawn(A);
1110 world.spawn_empty();
1111
1112 let system = (LocalBuilder(0), ParamBuilder)
1113 .build_state(&mut world)
1114 .build_system(multi_param_system);
1115
1116 let output = world.run_system_once(system).unwrap();
1117 assert_eq!(output, 1);
1118
1119 let builder_system = (LocalBuilder(0), ParamBuilder).build_system(multi_param_system);
1120
1121 let output = world.run_system_once(builder_system).unwrap();
1122 assert_eq!(output, 1);
1123 }
1124
1125 #[test]
1126 fn vec_builder() {
1127 let mut world = World::new();
1128
1129 world.spawn((A, B, C));
1130 world.spawn((A, B));
1131 world.spawn((A, C));
1132 world.spawn((A, C));
1133 world.spawn_empty();
1134
1135 let system = (vec![
1136 QueryParamBuilder::new_box(|builder| {
1137 builder.with::<B>().without::<C>();
1138 }),
1139 QueryParamBuilder::new_box(|builder| {
1140 builder.with::<C>().without::<B>();
1141 }),
1142 ],)
1143 .build_state(&mut world)
1144 .build_system(|params: Vec<Query<&mut A>>| {
1145 let mut count: usize = 0;
1146 params
1147 .into_iter()
1148 .for_each(|mut query| count += query.iter_mut().count());
1149 count
1150 });
1151
1152 let output = world.run_system_once(system).unwrap();
1155 assert_eq!(output, 3);
1156 }
1157
1158 #[test]
1159 fn multi_param_builder_inference() {
1160 let mut world = World::new();
1161
1162 world.spawn(A);
1163 world.spawn_empty();
1164
1165 let system = (LocalBuilder(0u64), ParamBuilder::local::<u64>())
1166 .build_state(&mut world)
1167 .build_system(|a, b| *a + *b + 1);
1168
1169 let output = world.run_system_once(system).unwrap();
1172 assert_eq!(output, 1);
1173 }
1174
1175 #[test]
1176 fn param_set_builder() {
1177 let mut world = World::new();
1178
1179 world.spawn((A, B, C));
1180 world.spawn((A, B));
1181 world.spawn((A, C));
1182 world.spawn((A, C));
1183 world.spawn_empty();
1184
1185 let system = (ParamSetBuilder((
1186 QueryParamBuilder::new(|builder| {
1187 builder.with::<B>();
1188 }),
1189 QueryParamBuilder::new(|builder| {
1190 builder.with::<C>();
1191 }),
1192 )),)
1193 .build_state(&mut world)
1194 .build_system(|mut params: ParamSet<(Query<&mut A>, Query<&mut A>)>| {
1195 params.p0().iter().count() + params.p1().iter().count()
1196 });
1197
1198 let output = world.run_system_once(system).unwrap();
1199 assert_eq!(output, 5);
1200
1201 let builder_system = (ParamSetBuilder((
1202 QueryParamBuilder::new(|builder| {
1203 builder.with::<B>();
1204 }),
1205 QueryParamBuilder::new(|builder| {
1206 builder.with::<C>();
1207 }),
1208 )),)
1209 .build_system(|mut params: ParamSet<(Query<&mut A>, Query<&mut A>)>| {
1210 params.p0().iter().count() + params.p1().iter().count()
1211 });
1212
1213 let output = world.run_system_once(builder_system).unwrap();
1214 assert_eq!(output, 5);
1215 }
1216
1217 #[test]
1218 fn param_set_vec_builder() {
1219 let mut world = World::new();
1220
1221 world.spawn((A, B, C));
1222 world.spawn((A, B));
1223 world.spawn((A, C));
1224 world.spawn((A, C));
1225 world.spawn_empty();
1226
1227 let system = (ParamSetBuilder(vec![
1228 QueryParamBuilder::new_box(|builder| {
1229 builder.with::<B>();
1230 }),
1231 QueryParamBuilder::new_box(|builder| {
1232 builder.with::<C>();
1233 }),
1234 ]),)
1235 .build_state(&mut world)
1236 .build_system(|mut params: ParamSet<Vec<Query<&mut A>>>| {
1237 let mut count = 0;
1238 params.for_each(|mut query| count += query.iter_mut().count());
1239 count
1240 });
1241
1242 let output = world.run_system_once(system).unwrap();
1245 assert_eq!(output, 5);
1246 }
1247
1248 #[test]
1249 fn dyn_builder() {
1250 let mut world = World::new();
1251
1252 world.spawn(A);
1253 world.spawn_empty();
1254
1255 let system = (
1256 DynParamBuilder::new(LocalBuilder(3_usize)),
1257 DynParamBuilder::new::<Query<()>>(QueryParamBuilder::new(|builder| {
1258 builder.with::<A>();
1259 })),
1260 DynParamBuilder::new::<&Entities>(ParamBuilder),
1261 )
1262 .build_state(&mut world)
1263 .build_system(
1264 |mut p0: DynSystemParam, mut p1: DynSystemParam, mut p2: DynSystemParam| {
1265 let local = *p0.downcast_mut::<Local<usize>>().unwrap();
1266 let query_count = p1.downcast_mut::<Query<()>>().unwrap().iter().count();
1267 let _entities = p2.downcast_mut::<&Entities>().unwrap();
1268 assert!(p0.downcast_mut::<Query<()>>().is_none());
1269 local + query_count
1270 },
1271 );
1272
1273 let output = world.run_system_once(system).unwrap();
1276 assert_eq!(output, 4);
1277 }
1278
1279 #[derive(SystemParam)]
1280 #[system_param(builder)]
1281 struct CustomParam<'w, 's> {
1282 query: Query<'w, 's, ()>,
1283 local: Local<'s, usize>,
1284 }
1285
1286 #[test]
1287 fn custom_param_builder() {
1288 let mut world = World::new();
1289
1290 world.spawn(A);
1291 world.spawn_empty();
1292
1293 let system = (CustomParamBuilder {
1294 local: LocalBuilder(100),
1295 query: QueryParamBuilder::new(|builder| {
1296 builder.with::<A>();
1297 }),
1298 },)
1299 .build_state(&mut world)
1300 .build_system(|param: CustomParam| *param.local + param.query.iter().count());
1301
1302 let output = world.run_system_once(system).unwrap();
1303 assert_eq!(output, 101);
1304
1305 let builder_system = (CustomParamBuilder {
1306 local: LocalBuilder(100),
1307 query: QueryParamBuilder::new(|builder| {
1308 builder.with::<A>();
1309 }),
1310 },)
1311 .build_system(|param: CustomParam| *param.local + param.query.iter().count());
1312
1313 let output = world.run_system_once(builder_system).unwrap();
1314 assert_eq!(output, 101);
1315 }
1316
1317 #[test]
1318 #[expect(deprecated, reason = "`FilteredResources` will be removed.")]
1319 fn filtered_resource_conflicts_read_with_res() {
1320 let mut world = World::new();
1321 (
1322 ParamBuilder::resource(),
1323 FilteredResourcesParamBuilder::new(|builder| {
1324 builder.add_read::<R>();
1325 }),
1326 )
1327 .build_state(&mut world)
1328 .build_system(|_r: Res<R>, _fr: FilteredResources| {});
1329 }
1330
1331 #[test]
1332 #[should_panic]
1333 #[expect(deprecated, reason = "`FilteredResources` will be removed.")]
1334 fn filtered_resource_conflicts_read_with_resmut() {
1335 let mut world = World::new();
1336 (
1337 ParamBuilder::resource_mut(),
1338 FilteredResourcesParamBuilder::new(|builder| {
1339 builder.add_read::<R>();
1340 }),
1341 )
1342 .build_state(&mut world)
1343 .build_system(|_r: ResMut<R>, _fr: FilteredResources| {});
1344 }
1345
1346 #[test]
1347 #[should_panic]
1348 #[expect(deprecated, reason = "`FilteredResources` will be removed.")]
1349 fn filtered_resource_conflicts_read_all_with_resmut() {
1350 let mut world = World::new();
1351 (
1352 ParamBuilder::resource_mut(),
1353 FilteredResourcesParamBuilder::new(|builder| {
1354 builder.add_read_all();
1355 }),
1356 )
1357 .build_state(&mut world)
1358 .build_system(|_r: ResMut<R>, _fr: FilteredResources| {});
1359 }
1360
1361 #[test]
1362 #[expect(deprecated, reason = "`FilteredResourcesMut` will be removed.")]
1363 fn filtered_resource_mut_conflicts_read_with_res() {
1364 let mut world = World::new();
1365 (
1366 ParamBuilder::resource(),
1367 FilteredResourcesMutParamBuilder::new(|builder| {
1368 builder.add_read::<R>();
1369 }),
1370 )
1371 .build_state(&mut world)
1372 .build_system(|_r: Res<R>, _fr: FilteredResourcesMut| {});
1373 }
1374
1375 #[test]
1376 #[should_panic]
1377 #[expect(deprecated, reason = "`FilteredResourcesMut` will be removed.")]
1378 fn filtered_resource_mut_conflicts_read_with_resmut() {
1379 let mut world = World::new();
1380 (
1381 ParamBuilder::resource_mut(),
1382 FilteredResourcesMutParamBuilder::new(|builder| {
1383 builder.add_read::<R>();
1384 }),
1385 )
1386 .build_state(&mut world)
1387 .build_system(|_r: ResMut<R>, _fr: FilteredResourcesMut| {});
1388 }
1389
1390 #[test]
1391 #[should_panic]
1392 #[expect(deprecated, reason = "`FilteredResourcesMut` will be removed.")]
1393 fn filtered_resource_mut_conflicts_write_with_res() {
1394 let mut world = World::new();
1395 (
1396 ParamBuilder::resource(),
1397 FilteredResourcesMutParamBuilder::new(|builder| {
1398 builder.add_write::<R>();
1399 }),
1400 )
1401 .build_state(&mut world)
1402 .build_system(|_r: Res<R>, _fr: FilteredResourcesMut| {});
1403 }
1404
1405 #[test]
1406 #[should_panic]
1407 #[expect(deprecated, reason = "`FilteredResourcesMut` will be removed.")]
1408 fn filtered_resource_mut_conflicts_write_all_with_res() {
1409 let mut world = World::new();
1410 (
1411 ParamBuilder::resource(),
1412 FilteredResourcesMutParamBuilder::new(|builder| {
1413 builder.add_write_all();
1414 }),
1415 )
1416 .build_state(&mut world)
1417 .build_system(|_r: Res<R>, _fr: FilteredResourcesMut| {});
1418 }
1419
1420 #[test]
1421 #[should_panic]
1422 #[expect(deprecated, reason = "`FilteredResourcesMut` will be removed.")]
1423 fn filtered_resource_mut_conflicts_write_with_resmut() {
1424 let mut world = World::new();
1425 (
1426 ParamBuilder::resource_mut(),
1427 FilteredResourcesMutParamBuilder::new(|builder| {
1428 builder.add_write::<R>();
1429 }),
1430 )
1431 .build_state(&mut world)
1432 .build_system(|_r: ResMut<R>, _fr: FilteredResourcesMut| {});
1433 }
1434}