1use bevy_utils::all_tuples;
2
3use crate::{
4 schedule::{
5 condition::{BoxedCondition, Condition},
6 graph_utils::{Ambiguity, Dependency, DependencyKind, GraphInfo},
7 set::{InternedSystemSet, IntoSystemSet, SystemSet},
8 Chain,
9 },
10 system::{BoxedSystem, IntoSystem, System},
11};
12
13fn new_condition<M>(condition: impl Condition<M>) -> BoxedCondition {
14 let condition_system = IntoSystem::into_system(condition);
15 assert!(
16 condition_system.is_send(),
17 "Condition `{}` accesses `NonSend` resources. This is not currently supported.",
18 condition_system.name()
19 );
20
21 Box::new(condition_system)
22}
23
24fn ambiguous_with(graph_info: &mut GraphInfo, set: InternedSystemSet) {
25 match &mut graph_info.ambiguous_with {
26 detection @ Ambiguity::Check => {
27 *detection = Ambiguity::IgnoreWithSet(vec![set]);
28 }
29 Ambiguity::IgnoreWithSet(ambiguous_with) => {
30 ambiguous_with.push(set);
31 }
32 Ambiguity::IgnoreAll => (),
33 }
34}
35
36impl<Marker, F> IntoSystemConfigs<Marker> for F
37where
38 F: IntoSystem<(), (), Marker>,
39{
40 fn into_configs(self) -> SystemConfigs {
41 SystemConfigs::new_system(Box::new(IntoSystem::into_system(self)))
42 }
43}
44
45impl IntoSystemConfigs<()> for BoxedSystem<(), ()> {
46 fn into_configs(self) -> SystemConfigs {
47 SystemConfigs::new_system(self)
48 }
49}
50
51pub struct NodeConfig<T> {
58 pub(crate) node: T,
59 pub(crate) graph_info: GraphInfo,
61 pub(crate) conditions: Vec<BoxedCondition>,
62}
63
64pub type SystemConfig = NodeConfig<BoxedSystem>;
66
67pub enum NodeConfigs<T> {
69 NodeConfig(NodeConfig<T>),
71 Configs {
73 configs: Vec<NodeConfigs<T>>,
75 collective_conditions: Vec<BoxedCondition>,
77 chained: Chain,
79 },
80}
81
82pub type SystemConfigs = NodeConfigs<BoxedSystem>;
84
85impl SystemConfigs {
86 fn new_system(system: BoxedSystem) -> Self {
87 let sets = system.default_system_sets().into_iter().collect();
89 Self::NodeConfig(SystemConfig {
90 node: system,
91 graph_info: GraphInfo {
92 hierarchy: sets,
93 ..Default::default()
94 },
95 conditions: Vec::new(),
96 })
97 }
98}
99
100impl<T> NodeConfigs<T> {
101 pub fn in_set_inner(&mut self, set: InternedSystemSet) {
103 match self {
104 Self::NodeConfig(config) => {
105 config.graph_info.hierarchy.push(set);
106 }
107 Self::Configs { configs, .. } => {
108 for config in configs {
109 config.in_set_inner(set);
110 }
111 }
112 }
113 }
114
115 fn before_inner(&mut self, set: InternedSystemSet) {
116 match self {
117 Self::NodeConfig(config) => {
118 config
119 .graph_info
120 .dependencies
121 .push(Dependency::new(DependencyKind::Before, set));
122 }
123 Self::Configs { configs, .. } => {
124 for config in configs {
125 config.before_inner(set);
126 }
127 }
128 }
129 }
130
131 fn after_inner(&mut self, set: InternedSystemSet) {
132 match self {
133 Self::NodeConfig(config) => {
134 config
135 .graph_info
136 .dependencies
137 .push(Dependency::new(DependencyKind::After, set));
138 }
139 Self::Configs { configs, .. } => {
140 for config in configs {
141 config.after_inner(set);
142 }
143 }
144 }
145 }
146
147 fn before_ignore_deferred_inner(&mut self, set: InternedSystemSet) {
148 match self {
149 Self::NodeConfig(config) => {
150 config
151 .graph_info
152 .dependencies
153 .push(Dependency::new(DependencyKind::BeforeNoSync, set));
154 }
155 Self::Configs { configs, .. } => {
156 for config in configs {
157 config.before_ignore_deferred_inner(set.intern());
158 }
159 }
160 }
161 }
162
163 fn after_ignore_deferred_inner(&mut self, set: InternedSystemSet) {
164 match self {
165 Self::NodeConfig(config) => {
166 config
167 .graph_info
168 .dependencies
169 .push(Dependency::new(DependencyKind::AfterNoSync, set));
170 }
171 Self::Configs { configs, .. } => {
172 for config in configs {
173 config.after_ignore_deferred_inner(set.intern());
174 }
175 }
176 }
177 }
178
179 fn distributive_run_if_inner<M>(&mut self, condition: impl Condition<M> + Clone) {
180 match self {
181 Self::NodeConfig(config) => {
182 config.conditions.push(new_condition(condition));
183 }
184 Self::Configs { configs, .. } => {
185 for config in configs {
186 config.distributive_run_if_inner(condition.clone());
187 }
188 }
189 }
190 }
191
192 fn ambiguous_with_inner(&mut self, set: InternedSystemSet) {
193 match self {
194 Self::NodeConfig(config) => {
195 ambiguous_with(&mut config.graph_info, set);
196 }
197 Self::Configs { configs, .. } => {
198 for config in configs {
199 config.ambiguous_with_inner(set);
200 }
201 }
202 }
203 }
204
205 fn ambiguous_with_all_inner(&mut self) {
206 match self {
207 Self::NodeConfig(config) => {
208 config.graph_info.ambiguous_with = Ambiguity::IgnoreAll;
209 }
210 Self::Configs { configs, .. } => {
211 for config in configs {
212 config.ambiguous_with_all_inner();
213 }
214 }
215 }
216 }
217
218 pub fn run_if_dyn(&mut self, condition: BoxedCondition) {
223 match self {
224 Self::NodeConfig(config) => {
225 config.conditions.push(condition);
226 }
227 Self::Configs {
228 collective_conditions,
229 ..
230 } => {
231 collective_conditions.push(condition);
232 }
233 }
234 }
235
236 fn chain_inner(mut self) -> Self {
237 match &mut self {
238 Self::NodeConfig(_) => { }
239 Self::Configs { chained, .. } => {
240 *chained = Chain::Yes;
241 }
242 }
243 self
244 }
245
246 fn chain_ignore_deferred_inner(mut self) -> Self {
247 match &mut self {
248 Self::NodeConfig(_) => { }
249 Self::Configs { chained, .. } => {
250 *chained = Chain::YesIgnoreDeferred;
251 }
252 }
253 self
254 }
255}
256
257#[diagnostic::on_unimplemented(
292 message = "`{Self}` does not describe a valid system configuration",
293 label = "invalid system configuration"
294)]
295pub trait IntoSystemConfigs<Marker>
296where
297 Self: Sized,
298{
299 fn into_configs(self) -> SystemConfigs;
301
302 #[track_caller]
304 fn in_set(self, set: impl SystemSet) -> SystemConfigs {
305 self.into_configs().in_set(set)
306 }
307
308 fn before<M>(self, set: impl IntoSystemSet<M>) -> SystemConfigs {
317 self.into_configs().before(set)
318 }
319
320 fn after<M>(self, set: impl IntoSystemSet<M>) -> SystemConfigs {
329 self.into_configs().after(set)
330 }
331
332 fn before_ignore_deferred<M>(self, set: impl IntoSystemSet<M>) -> SystemConfigs {
337 self.into_configs().before_ignore_deferred(set)
338 }
339
340 fn after_ignore_deferred<M>(self, set: impl IntoSystemSet<M>) -> SystemConfigs {
345 self.into_configs().after_ignore_deferred(set)
346 }
347
348 fn distributive_run_if<M>(self, condition: impl Condition<M> + Clone) -> SystemConfigs {
379 self.into_configs().distributive_run_if(condition)
380 }
381
382 fn run_if<M>(self, condition: impl Condition<M>) -> SystemConfigs {
413 self.into_configs().run_if(condition)
414 }
415
416 fn ambiguous_with<M>(self, set: impl IntoSystemSet<M>) -> SystemConfigs {
419 self.into_configs().ambiguous_with(set)
420 }
421
422 fn ambiguous_with_all(self) -> SystemConfigs {
425 self.into_configs().ambiguous_with_all()
426 }
427
428 fn chain(self) -> SystemConfigs {
436 self.into_configs().chain()
437 }
438
439 fn chain_ignore_deferred(self) -> SystemConfigs {
445 self.into_configs().chain_ignore_deferred()
446 }
447}
448
449impl IntoSystemConfigs<()> for SystemConfigs {
450 fn into_configs(self) -> Self {
451 self
452 }
453
454 #[track_caller]
455 fn in_set(mut self, set: impl SystemSet) -> Self {
456 assert!(
457 set.system_type().is_none(),
458 "adding arbitrary systems to a system type set is not allowed"
459 );
460
461 self.in_set_inner(set.intern());
462
463 self
464 }
465
466 fn before<M>(mut self, set: impl IntoSystemSet<M>) -> Self {
467 let set = set.into_system_set();
468 self.before_inner(set.intern());
469 self
470 }
471
472 fn after<M>(mut self, set: impl IntoSystemSet<M>) -> Self {
473 let set = set.into_system_set();
474 self.after_inner(set.intern());
475 self
476 }
477
478 fn before_ignore_deferred<M>(mut self, set: impl IntoSystemSet<M>) -> Self {
479 let set = set.into_system_set();
480 self.before_ignore_deferred_inner(set.intern());
481 self
482 }
483
484 fn after_ignore_deferred<M>(mut self, set: impl IntoSystemSet<M>) -> Self {
485 let set = set.into_system_set();
486 self.after_ignore_deferred_inner(set.intern());
487 self
488 }
489
490 fn distributive_run_if<M>(mut self, condition: impl Condition<M> + Clone) -> SystemConfigs {
491 self.distributive_run_if_inner(condition);
492 self
493 }
494
495 fn run_if<M>(mut self, condition: impl Condition<M>) -> SystemConfigs {
496 self.run_if_dyn(new_condition(condition));
497 self
498 }
499
500 fn ambiguous_with<M>(mut self, set: impl IntoSystemSet<M>) -> Self {
501 let set = set.into_system_set();
502 self.ambiguous_with_inner(set.intern());
503 self
504 }
505
506 fn ambiguous_with_all(mut self) -> Self {
507 self.ambiguous_with_all_inner();
508 self
509 }
510
511 fn chain(self) -> Self {
512 self.chain_inner()
513 }
514
515 fn chain_ignore_deferred(self) -> Self {
516 self.chain_ignore_deferred_inner()
517 }
518}
519
520#[doc(hidden)]
521pub struct SystemConfigTupleMarker;
522
523macro_rules! impl_system_collection {
524 ($(($param: ident, $sys: ident)),*) => {
525 impl<$($param, $sys),*> IntoSystemConfigs<(SystemConfigTupleMarker, $($param,)*)> for ($($sys,)*)
526 where
527 $($sys: IntoSystemConfigs<$param>),*
528 {
529 #[allow(non_snake_case)]
530 fn into_configs(self) -> SystemConfigs {
531 let ($($sys,)*) = self;
532 SystemConfigs::Configs {
533 configs: vec![$($sys.into_configs(),)*],
534 collective_conditions: Vec::new(),
535 chained: Chain::No,
536 }
537 }
538 }
539 }
540}
541
542all_tuples!(impl_system_collection, 1, 20, P, S);
543
544pub type SystemSetConfig = NodeConfig<InternedSystemSet>;
546
547impl SystemSetConfig {
548 #[track_caller]
549 pub(super) fn new(set: InternedSystemSet) -> Self {
550 assert!(
553 set.system_type().is_none(),
554 "configuring system type sets is not allowed"
555 );
556
557 Self {
558 node: set,
559 graph_info: GraphInfo::default(),
560 conditions: Vec::new(),
561 }
562 }
563}
564
565pub type SystemSetConfigs = NodeConfigs<InternedSystemSet>;
567
568#[diagnostic::on_unimplemented(
570 message = "`{Self}` does not describe a valid system set configuration",
571 label = "invalid system set configuration"
572)]
573pub trait IntoSystemSetConfigs
574where
575 Self: Sized,
576{
577 #[doc(hidden)]
579 fn into_configs(self) -> SystemSetConfigs;
580
581 #[track_caller]
583 fn in_set(self, set: impl SystemSet) -> SystemSetConfigs {
584 self.into_configs().in_set(set)
585 }
586
587 fn before<M>(self, set: impl IntoSystemSet<M>) -> SystemSetConfigs {
593 self.into_configs().before(set)
594 }
595
596 fn after<M>(self, set: impl IntoSystemSet<M>) -> SystemSetConfigs {
602 self.into_configs().after(set)
603 }
604
605 fn before_ignore_deferred<M>(self, set: impl IntoSystemSet<M>) -> SystemSetConfigs {
610 self.into_configs().before_ignore_deferred(set)
611 }
612
613 fn after_ignore_deferred<M>(self, set: impl IntoSystemSet<M>) -> SystemSetConfigs {
618 self.into_configs().after_ignore_deferred(set)
619 }
620
621 fn run_if<M>(self, condition: impl Condition<M>) -> SystemSetConfigs {
626 self.into_configs().run_if(condition)
627 }
628
629 fn ambiguous_with<M>(self, set: impl IntoSystemSet<M>) -> SystemSetConfigs {
632 self.into_configs().ambiguous_with(set)
633 }
634
635 fn ambiguous_with_all(self) -> SystemSetConfigs {
638 self.into_configs().ambiguous_with_all()
639 }
640
641 fn chain(self) -> SystemSetConfigs {
645 self.into_configs().chain()
646 }
647
648 fn chain_ignore_deferred(self) -> SystemConfigs {
654 self.into_configs().chain_ignore_deferred()
655 }
656}
657
658impl IntoSystemSetConfigs for SystemSetConfigs {
659 fn into_configs(self) -> Self {
660 self
661 }
662
663 #[track_caller]
664 fn in_set(mut self, set: impl SystemSet) -> Self {
665 assert!(
666 set.system_type().is_none(),
667 "adding arbitrary systems to a system type set is not allowed"
668 );
669 self.in_set_inner(set.intern());
670
671 self
672 }
673
674 fn before<M>(mut self, set: impl IntoSystemSet<M>) -> Self {
675 let set = set.into_system_set();
676 self.before_inner(set.intern());
677
678 self
679 }
680
681 fn after<M>(mut self, set: impl IntoSystemSet<M>) -> Self {
682 let set = set.into_system_set();
683 self.after_inner(set.intern());
684
685 self
686 }
687
688 fn before_ignore_deferred<M>(mut self, set: impl IntoSystemSet<M>) -> Self {
689 let set = set.into_system_set();
690 self.before_ignore_deferred_inner(set.intern());
691
692 self
693 }
694
695 fn after_ignore_deferred<M>(mut self, set: impl IntoSystemSet<M>) -> Self {
696 let set = set.into_system_set();
697 self.after_ignore_deferred_inner(set.intern());
698
699 self
700 }
701
702 fn run_if<M>(mut self, condition: impl Condition<M>) -> SystemSetConfigs {
703 self.run_if_dyn(new_condition(condition));
704
705 self
706 }
707
708 fn ambiguous_with<M>(mut self, set: impl IntoSystemSet<M>) -> Self {
709 let set = set.into_system_set();
710 self.ambiguous_with_inner(set.intern());
711
712 self
713 }
714
715 fn ambiguous_with_all(mut self) -> Self {
716 self.ambiguous_with_all_inner();
717
718 self
719 }
720
721 fn chain(self) -> Self {
722 self.chain_inner()
723 }
724}
725
726impl<S: SystemSet> IntoSystemSetConfigs for S {
727 fn into_configs(self) -> SystemSetConfigs {
728 SystemSetConfigs::NodeConfig(SystemSetConfig::new(self.intern()))
729 }
730}
731
732impl IntoSystemSetConfigs for SystemSetConfig {
733 fn into_configs(self) -> SystemSetConfigs {
734 SystemSetConfigs::NodeConfig(self)
735 }
736}
737
738macro_rules! impl_system_set_collection {
739 ($($set: ident),*) => {
740 impl<$($set: IntoSystemSetConfigs),*> IntoSystemSetConfigs for ($($set,)*)
741 {
742 #[allow(non_snake_case)]
743 fn into_configs(self) -> SystemSetConfigs {
744 let ($($set,)*) = self;
745 SystemSetConfigs::Configs {
746 configs: vec![$($set.into_configs(),)*],
747 collective_conditions: Vec::new(),
748 chained: Chain::No,
749 }
750 }
751 }
752 }
753}
754
755all_tuples!(impl_system_set_collection, 1, 20, S);