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
28pub unsafe trait SystemParamBuilder<P: SystemParam>: Sized {
133 fn build(self, world: &mut World) -> P::State;
136
137 fn build_state(self, world: &mut World) -> SystemState<P> {
140 SystemState::from_builder(world, self)
141 }
142
143 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#[derive(Default, Debug, Clone)]
210pub struct ParamBuilder;
211
212unsafe 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 pub fn of<T: SystemParam>() -> impl SystemParamBuilder<T> {
222 Self
223 }
224
225 pub fn resource<'w, T: Resource>() -> impl SystemParamBuilder<Res<'w, T>> {
227 Self
228 }
229
230 pub fn resource_mut<'w, T: Resource<Mutability = Mutable>>(
232 ) -> impl SystemParamBuilder<ResMut<'w, T>> {
233 Self
234 }
235
236 pub fn local<'s, T: FromWorld + Send + 'static>() -> impl SystemParamBuilder<Local<'s, T>> {
238 Self
239 }
240
241 pub fn query<'w, 's, D: QueryData + 'static>() -> impl SystemParamBuilder<Query<'w, 's, D, ()>>
243 {
244 Self
245 }
246
247 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#[doc(hidden)]
256pub struct IsBuilderSystem;
257
258pub 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 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
300pub 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 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 Initialized {
334 system: FunctionSystem<Marker, In, Out, Func>,
335 },
336 Uninitialized {
339 builder: Builder,
340 func: Func,
341 meta: SystemMeta,
342 },
343 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 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
473unsafe 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 FunctionSystem<Marker, In, Out, Func>: ReadOnlySystem,
484{
485}
486
487unsafe 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#[derive(Clone)]
539pub struct QueryParamBuilder<T>(T);
540
541impl<T> QueryParamBuilder<T> {
542 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 pub fn new_box(f: impl FnOnce(&mut QueryBuilder<D, F>) + 'a) -> Self {
557 Self(Box::new(f))
558 }
559}
560
561unsafe 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 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
616unsafe 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
625unsafe 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#[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 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
736unsafe 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
748pub struct DynParamBuilder<'a>(Box<dyn FnOnce(&mut World) -> DynSystemParamState + 'a>);
751
752impl<'a> DynParamBuilder<'a> {
753 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
762unsafe 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#[derive(Default, Debug, Clone)]
791pub struct LocalBuilder<T>(pub T);
792
793unsafe 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#[derive(Clone)]
805pub struct FilteredResourcesParamBuilder<T>(T);
806
807impl<T> FilteredResourcesParamBuilder<T> {
808 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 pub fn new_box(f: impl FnOnce(&mut FilteredResourcesBuilder) + 'a) -> Self {
821 Self(Box::new(f))
822 }
823}
824
825unsafe 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#[derive(Clone)]
839pub struct FilteredResourcesMutParamBuilder<T>(T);
840
841impl<T> FilteredResourcesMutParamBuilder<T> {
842 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 pub fn new_box(f: impl FnOnce(&mut FilteredResourcesMutBuilder) + 'a) -> Self {
855 Self(Box::new(f))
856 }
857}
858
859unsafe 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#[derive(Clone)]
872pub struct OptionBuilder<T>(T);
873
874unsafe 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#[derive(Clone)]
885pub struct ResultBuilder<T>(T);
886
887unsafe 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#[derive(Clone)]
901pub struct IfBuilder<T>(T);
902
903unsafe 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 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 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 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 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 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 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 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 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}