bevy_ecs/schedule/config.rs
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
36/// Stores configuration for a single generic node (a system or a system set)
37///
38/// The configuration includes the node itself, scheduling metadata
39/// (hierarchy: in which sets is the node contained,
40/// dependencies: before/after which other nodes should this node run)
41/// and the run conditions associated with this node.
42pub struct NodeConfig<T> {
43 pub(crate) node: T,
44 /// Hierarchy and dependency metadata for this node
45 pub(crate) graph_info: GraphInfo,
46 pub(crate) conditions: Vec<BoxedCondition>,
47}
48
49/// Stores configuration for a single system.
50pub type SystemConfig = NodeConfig<BoxedSystem>;
51
52/// A collections of generic [`NodeConfig`]s.
53pub enum NodeConfigs<T> {
54 /// Configuration for a single node.
55 NodeConfig(NodeConfig<T>),
56 /// Configuration for a tuple of nested `Configs` instances.
57 Configs {
58 /// Configuration for each element of the tuple.
59 configs: Vec<NodeConfigs<T>>,
60 /// Run conditions applied to everything in the tuple.
61 collective_conditions: Vec<BoxedCondition>,
62 /// See [`Chain`] for usage.
63 chained: Chain,
64 },
65}
66
67/// A collection of [`SystemConfig`].
68pub type SystemConfigs = NodeConfigs<BoxedSystem>;
69
70impl SystemConfigs {
71 fn new_system(system: BoxedSystem) -> Self {
72 // include system in its default sets
73 let sets = system.default_system_sets().into_iter().collect();
74 Self::NodeConfig(SystemConfig {
75 node: system,
76 graph_info: GraphInfo {
77 hierarchy: sets,
78 ..Default::default()
79 },
80 conditions: Vec::new(),
81 })
82 }
83}
84
85impl<T> NodeConfigs<T> {
86 /// Adds a new boxed system set to the systems.
87 pub fn in_set_inner(&mut self, set: InternedSystemSet) {
88 match self {
89 Self::NodeConfig(config) => {
90 config.graph_info.hierarchy.push(set);
91 }
92 Self::Configs { configs, .. } => {
93 for config in configs {
94 config.in_set_inner(set);
95 }
96 }
97 }
98 }
99
100 fn before_inner(&mut self, set: InternedSystemSet) {
101 match self {
102 Self::NodeConfig(config) => {
103 config
104 .graph_info
105 .dependencies
106 .push(Dependency::new(DependencyKind::Before, set));
107 }
108 Self::Configs { configs, .. } => {
109 for config in configs {
110 config.before_inner(set);
111 }
112 }
113 }
114 }
115
116 fn after_inner(&mut self, set: InternedSystemSet) {
117 match self {
118 Self::NodeConfig(config) => {
119 config
120 .graph_info
121 .dependencies
122 .push(Dependency::new(DependencyKind::After, set));
123 }
124 Self::Configs { configs, .. } => {
125 for config in configs {
126 config.after_inner(set);
127 }
128 }
129 }
130 }
131
132 fn before_ignore_deferred_inner(&mut self, set: InternedSystemSet) {
133 match self {
134 Self::NodeConfig(config) => {
135 config
136 .graph_info
137 .dependencies
138 .push(Dependency::new(DependencyKind::BeforeNoSync, set));
139 }
140 Self::Configs { configs, .. } => {
141 for config in configs {
142 config.before_ignore_deferred_inner(set.intern());
143 }
144 }
145 }
146 }
147
148 fn after_ignore_deferred_inner(&mut self, set: InternedSystemSet) {
149 match self {
150 Self::NodeConfig(config) => {
151 config
152 .graph_info
153 .dependencies
154 .push(Dependency::new(DependencyKind::AfterNoSync, set));
155 }
156 Self::Configs { configs, .. } => {
157 for config in configs {
158 config.after_ignore_deferred_inner(set.intern());
159 }
160 }
161 }
162 }
163
164 fn distributive_run_if_inner<M>(&mut self, condition: impl Condition<M> + Clone) {
165 match self {
166 Self::NodeConfig(config) => {
167 config.conditions.push(new_condition(condition));
168 }
169 Self::Configs { configs, .. } => {
170 for config in configs {
171 config.distributive_run_if_inner(condition.clone());
172 }
173 }
174 }
175 }
176
177 fn ambiguous_with_inner(&mut self, set: InternedSystemSet) {
178 match self {
179 Self::NodeConfig(config) => {
180 ambiguous_with(&mut config.graph_info, set);
181 }
182 Self::Configs { configs, .. } => {
183 for config in configs {
184 config.ambiguous_with_inner(set);
185 }
186 }
187 }
188 }
189
190 fn ambiguous_with_all_inner(&mut self) {
191 match self {
192 Self::NodeConfig(config) => {
193 config.graph_info.ambiguous_with = Ambiguity::IgnoreAll;
194 }
195 Self::Configs { configs, .. } => {
196 for config in configs {
197 config.ambiguous_with_all_inner();
198 }
199 }
200 }
201 }
202
203 /// Adds a new boxed run condition to the systems.
204 ///
205 /// This is useful if you have a run condition whose concrete type is unknown.
206 /// Prefer `run_if` for run conditions whose type is known at compile time.
207 pub fn run_if_dyn(&mut self, condition: BoxedCondition) {
208 match self {
209 Self::NodeConfig(config) => {
210 config.conditions.push(condition);
211 }
212 Self::Configs {
213 collective_conditions,
214 ..
215 } => {
216 collective_conditions.push(condition);
217 }
218 }
219 }
220
221 fn chain_inner(mut self) -> Self {
222 match &mut self {
223 Self::NodeConfig(_) => { /* no op */ }
224 Self::Configs { chained, .. } => {
225 *chained = Chain::Yes;
226 }
227 }
228 self
229 }
230
231 fn chain_ignore_deferred_inner(mut self) -> Self {
232 match &mut self {
233 Self::NodeConfig(_) => { /* no op */ }
234 Self::Configs { chained, .. } => {
235 *chained = Chain::YesIgnoreDeferred;
236 }
237 }
238 self
239 }
240}
241
242/// Types that can convert into a [`SystemConfigs`].
243///
244/// This trait is implemented for "systems" (functions whose arguments all implement
245/// [`SystemParam`](crate::system::SystemParam)), or tuples thereof.
246/// It is a common entry point for system configurations.
247///
248/// # Examples
249///
250/// ```
251/// # use bevy_ecs::schedule::IntoSystemConfigs;
252/// # struct AppMock;
253/// # struct Update;
254/// # impl AppMock {
255/// # pub fn add_systems<M>(
256/// # &mut self,
257/// # schedule: Update,
258/// # systems: impl IntoSystemConfigs<M>,
259/// # ) -> &mut Self { self }
260/// # }
261/// # let mut app = AppMock;
262///
263/// fn handle_input() {}
264///
265/// fn update_camera() {}
266/// fn update_character() {}
267///
268/// app.add_systems(
269/// Update,
270/// (
271/// handle_input,
272/// (update_camera, update_character).after(handle_input)
273/// )
274/// );
275/// ```
276#[diagnostic::on_unimplemented(
277 message = "`{Self}` does not describe a valid system configuration",
278 label = "invalid system configuration"
279)]
280pub trait IntoSystemConfigs<Marker>
281where
282 Self: Sized,
283{
284 /// Convert into a [`SystemConfigs`].
285 fn into_configs(self) -> SystemConfigs;
286
287 /// Add these systems to the provided `set`.
288 #[track_caller]
289 fn in_set(self, set: impl SystemSet) -> SystemConfigs {
290 self.into_configs().in_set(set)
291 }
292
293 /// Runs before all systems in `set`. If `self` has any systems that produce [`Commands`](crate::system::Commands)
294 /// or other [`Deferred`](crate::system::Deferred) operations, all systems in `set` will see their effect.
295 ///
296 /// If automatically inserting [`apply_deferred`](crate::schedule::apply_deferred) like
297 /// this isn't desired, use [`before_ignore_deferred`](Self::before_ignore_deferred) instead.
298 ///
299 /// Calling [`.chain`](Self::chain) is often more convenient and ensures that all systems are added to the schedule.
300 /// Please check the [caveats section of `.after`](Self::after) for details.
301 fn before<M>(self, set: impl IntoSystemSet<M>) -> SystemConfigs {
302 self.into_configs().before(set)
303 }
304
305 /// Run after all systems in `set`. If `set` has any systems that produce [`Commands`](crate::system::Commands)
306 /// or other [`Deferred`](crate::system::Deferred) operations, all systems in `self` will see their effect.
307 ///
308 /// If automatically inserting [`apply_deferred`](crate::schedule::apply_deferred) like
309 /// this isn't desired, use [`after_ignore_deferred`](Self::after_ignore_deferred) instead.
310 ///
311 /// Calling [`.chain`](Self::chain) is often more convenient and ensures that all systems are added to the schedule.
312 ///
313 /// # Caveats
314 ///
315 /// If you configure two [`System`]s like `(GameSystem::A).after(GameSystem::B)` or `(GameSystem::A).before(GameSystem::B)`, the `GameSystem::B` will not be automatically scheduled.
316 ///
317 /// This means that the system `GameSystem::A` and the system or systems in `GameSystem::B` will run independently of each other if `GameSystem::B` was never explicitly scheduled with [`configure_sets`]
318 /// If that is the case, `.after`/`.before` will not provide the desired behavior
319 /// and the systems can run in parallel or in any order determined by the scheduler.
320 /// Only use `after(GameSystem::B)` and `before(GameSystem::B)` when you know that `B` has already been scheduled for you,
321 /// e.g. when it was provided by Bevy or a third-party dependency,
322 /// or you manually scheduled it somewhere else in your app.
323 ///
324 /// Another caveat is that if `GameSystem::B` is placed in a different schedule than `GameSystem::A`,
325 /// any ordering calls between them—whether using `.before`, `.after`, or `.chain`—will be silently ignored.
326 ///
327 /// [`configure_sets`]: https://docs.rs/bevy/latest/bevy/app/struct.App.html#method.configure_sets
328 fn after<M>(self, set: impl IntoSystemSet<M>) -> SystemConfigs {
329 self.into_configs().after(set)
330 }
331
332 /// Run before all systems in `set`.
333 ///
334 /// Unlike [`before`](Self::before), this will not cause the systems in
335 /// `set` to wait for the deferred effects of `self` to be applied.
336 fn before_ignore_deferred<M>(self, set: impl IntoSystemSet<M>) -> SystemConfigs {
337 self.into_configs().before_ignore_deferred(set)
338 }
339
340 /// Run after all systems in `set`.
341 ///
342 /// Unlike [`after`](Self::after), this will not wait for the deferred
343 /// effects of systems in `set` to be applied.
344 fn after_ignore_deferred<M>(self, set: impl IntoSystemSet<M>) -> SystemConfigs {
345 self.into_configs().after_ignore_deferred(set)
346 }
347
348 /// Add a run condition to each contained system.
349 ///
350 /// Each system will receive its own clone of the [`Condition`] and will only run
351 /// if the `Condition` is true.
352 ///
353 /// Each individual condition will be evaluated at most once (per schedule run),
354 /// right before the corresponding system prepares to run.
355 ///
356 /// This is equivalent to calling [`run_if`](IntoSystemConfigs::run_if) on each individual
357 /// system, as shown below:
358 ///
359 /// ```
360 /// # use bevy_ecs::prelude::*;
361 /// # let mut schedule = Schedule::default();
362 /// # fn a() {}
363 /// # fn b() {}
364 /// # fn condition() -> bool { true }
365 /// schedule.add_systems((a, b).distributive_run_if(condition));
366 /// schedule.add_systems((a.run_if(condition), b.run_if(condition)));
367 /// ```
368 ///
369 /// # Note
370 ///
371 /// Because the conditions are evaluated separately for each system, there is no guarantee
372 /// that all evaluations in a single schedule run will yield the same result. If another
373 /// system is run inbetween two evaluations it could cause the result of the condition to change.
374 ///
375 /// Use [`run_if`](IntoSystemSetConfigs::run_if) on a [`SystemSet`] if you want to make sure
376 /// that either all or none of the systems are run, or you don't want to evaluate the run
377 /// condition for each contained system separately.
378 fn distributive_run_if<M>(self, condition: impl Condition<M> + Clone) -> SystemConfigs {
379 self.into_configs().distributive_run_if(condition)
380 }
381
382 /// Run the systems only if the [`Condition`] is `true`.
383 ///
384 /// The `Condition` will be evaluated at most once (per schedule run),
385 /// the first time a system in this set prepares to run.
386 ///
387 /// If this set contains more than one system, calling `run_if` is equivalent to adding each
388 /// system to a common set and configuring the run condition on that set, as shown below:
389 ///
390 /// # Examples
391 ///
392 /// ```
393 /// # use bevy_ecs::prelude::*;
394 /// # let mut schedule = Schedule::default();
395 /// # fn a() {}
396 /// # fn b() {}
397 /// # fn condition() -> bool { true }
398 /// # #[derive(SystemSet, Debug, Eq, PartialEq, Hash, Clone, Copy)]
399 /// # struct C;
400 /// schedule.add_systems((a, b).run_if(condition));
401 /// schedule.add_systems((a, b).in_set(C)).configure_sets(C.run_if(condition));
402 /// ```
403 ///
404 /// # Note
405 ///
406 /// Because the condition will only be evaluated once, there is no guarantee that the condition
407 /// is upheld after the first system has run. You need to make sure that no other systems that
408 /// could invalidate the condition are scheduled inbetween the first and last run system.
409 ///
410 /// Use [`distributive_run_if`](IntoSystemConfigs::distributive_run_if) if you want the
411 /// condition to be evaluated for each individual system, right before one is run.
412 fn run_if<M>(self, condition: impl Condition<M>) -> SystemConfigs {
413 self.into_configs().run_if(condition)
414 }
415
416 /// Suppress warnings and errors that would result from these systems having ambiguities
417 /// (conflicting access but indeterminate order) with systems in `set`.
418 fn ambiguous_with<M>(self, set: impl IntoSystemSet<M>) -> SystemConfigs {
419 self.into_configs().ambiguous_with(set)
420 }
421
422 /// Suppress warnings and errors that would result from these systems having ambiguities
423 /// (conflicting access but indeterminate order) with any other system.
424 fn ambiguous_with_all(self) -> SystemConfigs {
425 self.into_configs().ambiguous_with_all()
426 }
427
428 /// Treat this collection as a sequence of systems.
429 ///
430 /// Ordering constraints will be applied between the successive elements.
431 ///
432 /// If the preceding node on a edge has deferred parameters, a [`apply_deferred`](crate::schedule::apply_deferred)
433 /// will be inserted on the edge. If this behavior is not desired consider using
434 /// [`chain_ignore_deferred`](Self::chain_ignore_deferred) instead.
435 fn chain(self) -> SystemConfigs {
436 self.into_configs().chain()
437 }
438
439 /// Treat this collection as a sequence of systems.
440 ///
441 /// Ordering constraints will be applied between the successive elements.
442 ///
443 /// Unlike [`chain`](Self::chain) this will **not** add [`apply_deferred`](crate::schedule::apply_deferred) on the edges.
444 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
520impl<Marker, F> IntoSystemConfigs<Marker> for F
521where
522 F: IntoSystem<(), (), Marker>,
523{
524 fn into_configs(self) -> SystemConfigs {
525 SystemConfigs::new_system(Box::new(IntoSystem::into_system(self)))
526 }
527}
528
529impl IntoSystemConfigs<()> for BoxedSystem<(), ()> {
530 fn into_configs(self) -> SystemConfigs {
531 SystemConfigs::new_system(self)
532 }
533}
534
535#[doc(hidden)]
536pub struct SystemConfigTupleMarker;
537
538macro_rules! impl_system_collection {
539 ($(#[$meta:meta])* $(($param: ident, $sys: ident)),*) => {
540 $(#[$meta])*
541 impl<$($param, $sys),*> IntoSystemConfigs<(SystemConfigTupleMarker, $($param,)*)> for ($($sys,)*)
542 where
543 $($sys: IntoSystemConfigs<$param>),*
544 {
545 #[allow(non_snake_case)]
546 fn into_configs(self) -> SystemConfigs {
547 let ($($sys,)*) = self;
548 SystemConfigs::Configs {
549 configs: vec![$($sys.into_configs(),)*],
550 collective_conditions: Vec::new(),
551 chained: Chain::No,
552 }
553 }
554 }
555 }
556}
557
558all_tuples!(
559 #[doc(fake_variadic)]
560 impl_system_collection,
561 1,
562 20,
563 P,
564 S
565);
566
567/// A [`SystemSet`] with scheduling metadata.
568pub type SystemSetConfig = NodeConfig<InternedSystemSet>;
569
570impl SystemSetConfig {
571 #[track_caller]
572 pub(super) fn new(set: InternedSystemSet) -> Self {
573 // system type sets are automatically populated
574 // to avoid unintentionally broad changes, they cannot be configured
575 assert!(
576 set.system_type().is_none(),
577 "configuring system type sets is not allowed"
578 );
579
580 Self {
581 node: set,
582 graph_info: GraphInfo::default(),
583 conditions: Vec::new(),
584 }
585 }
586}
587
588/// A collection of [`SystemSetConfig`].
589pub type SystemSetConfigs = NodeConfigs<InternedSystemSet>;
590
591/// Types that can convert into a [`SystemSetConfigs`].
592#[diagnostic::on_unimplemented(
593 message = "`{Self}` does not describe a valid system set configuration",
594 label = "invalid system set configuration"
595)]
596pub trait IntoSystemSetConfigs
597where
598 Self: Sized,
599{
600 /// Convert into a [`SystemSetConfigs`].
601 #[doc(hidden)]
602 fn into_configs(self) -> SystemSetConfigs;
603
604 /// Add these system sets to the provided `set`.
605 #[track_caller]
606 fn in_set(self, set: impl SystemSet) -> SystemSetConfigs {
607 self.into_configs().in_set(set)
608 }
609
610 /// Runs before all systems in `set`. If `self` has any systems that produce [`Commands`](crate::system::Commands)
611 /// or other [`Deferred`](crate::system::Deferred) operations, all systems in `set` will see their effect.
612 ///
613 /// If automatically inserting [`apply_deferred`](crate::schedule::apply_deferred) like
614 /// this isn't desired, use [`before_ignore_deferred`](Self::before_ignore_deferred) instead.
615 fn before<M>(self, set: impl IntoSystemSet<M>) -> SystemSetConfigs {
616 self.into_configs().before(set)
617 }
618
619 /// Runs before all systems in `set`. If `set` has any systems that produce [`Commands`](crate::system::Commands)
620 /// or other [`Deferred`](crate::system::Deferred) operations, all systems in `self` will see their effect.
621 ///
622 /// If automatically inserting [`apply_deferred`](crate::schedule::apply_deferred) like
623 /// this isn't desired, use [`after_ignore_deferred`](Self::after_ignore_deferred) instead.
624 fn after<M>(self, set: impl IntoSystemSet<M>) -> SystemSetConfigs {
625 self.into_configs().after(set)
626 }
627
628 /// Run before all systems in `set`.
629 ///
630 /// Unlike [`before`](Self::before), this will not cause the systems in `set` to wait for the
631 /// deferred effects of `self` to be applied.
632 fn before_ignore_deferred<M>(self, set: impl IntoSystemSet<M>) -> SystemSetConfigs {
633 self.into_configs().before_ignore_deferred(set)
634 }
635
636 /// Run after all systems in `set`.
637 ///
638 /// Unlike [`after`](Self::after), this may not see the deferred
639 /// effects of systems in `set` to be applied.
640 fn after_ignore_deferred<M>(self, set: impl IntoSystemSet<M>) -> SystemSetConfigs {
641 self.into_configs().after_ignore_deferred(set)
642 }
643
644 /// Run the systems in this set(s) only if the [`Condition`] is `true`.
645 ///
646 /// The `Condition` will be evaluated at most once (per schedule run),
647 /// the first time a system in this set(s) prepares to run.
648 fn run_if<M>(self, condition: impl Condition<M>) -> SystemSetConfigs {
649 self.into_configs().run_if(condition)
650 }
651
652 /// Suppress warnings and errors that would result from systems in these sets having ambiguities
653 /// (conflicting access but indeterminate order) with systems in `set`.
654 fn ambiguous_with<M>(self, set: impl IntoSystemSet<M>) -> SystemSetConfigs {
655 self.into_configs().ambiguous_with(set)
656 }
657
658 /// Suppress warnings and errors that would result from systems in these sets having ambiguities
659 /// (conflicting access but indeterminate order) with any other system.
660 fn ambiguous_with_all(self) -> SystemSetConfigs {
661 self.into_configs().ambiguous_with_all()
662 }
663
664 /// Treat this collection as a sequence of system sets.
665 ///
666 /// Ordering constraints will be applied between the successive elements.
667 fn chain(self) -> SystemSetConfigs {
668 self.into_configs().chain()
669 }
670
671 /// Treat this collection as a sequence of systems.
672 ///
673 /// Ordering constraints will be applied between the successive elements.
674 ///
675 /// Unlike [`chain`](Self::chain) this will **not** add [`apply_deferred`](crate::schedule::apply_deferred) on the edges.
676 fn chain_ignore_deferred(self) -> SystemSetConfigs {
677 self.into_configs().chain_ignore_deferred()
678 }
679}
680
681impl IntoSystemSetConfigs for SystemSetConfigs {
682 fn into_configs(self) -> Self {
683 self
684 }
685
686 #[track_caller]
687 fn in_set(mut self, set: impl SystemSet) -> Self {
688 assert!(
689 set.system_type().is_none(),
690 "adding arbitrary systems to a system type set is not allowed"
691 );
692 self.in_set_inner(set.intern());
693
694 self
695 }
696
697 fn before<M>(mut self, set: impl IntoSystemSet<M>) -> Self {
698 let set = set.into_system_set();
699 self.before_inner(set.intern());
700
701 self
702 }
703
704 fn after<M>(mut self, set: impl IntoSystemSet<M>) -> Self {
705 let set = set.into_system_set();
706 self.after_inner(set.intern());
707
708 self
709 }
710
711 fn before_ignore_deferred<M>(mut self, set: impl IntoSystemSet<M>) -> Self {
712 let set = set.into_system_set();
713 self.before_ignore_deferred_inner(set.intern());
714
715 self
716 }
717
718 fn after_ignore_deferred<M>(mut self, set: impl IntoSystemSet<M>) -> Self {
719 let set = set.into_system_set();
720 self.after_ignore_deferred_inner(set.intern());
721
722 self
723 }
724
725 fn run_if<M>(mut self, condition: impl Condition<M>) -> SystemSetConfigs {
726 self.run_if_dyn(new_condition(condition));
727
728 self
729 }
730
731 fn ambiguous_with<M>(mut self, set: impl IntoSystemSet<M>) -> Self {
732 let set = set.into_system_set();
733 self.ambiguous_with_inner(set.intern());
734
735 self
736 }
737
738 fn ambiguous_with_all(mut self) -> Self {
739 self.ambiguous_with_all_inner();
740
741 self
742 }
743
744 fn chain(self) -> Self {
745 self.chain_inner()
746 }
747
748 fn chain_ignore_deferred(self) -> Self {
749 self.chain_ignore_deferred_inner()
750 }
751}
752
753impl<S: SystemSet> IntoSystemSetConfigs for S {
754 fn into_configs(self) -> SystemSetConfigs {
755 SystemSetConfigs::NodeConfig(SystemSetConfig::new(self.intern()))
756 }
757}
758
759impl IntoSystemSetConfigs for SystemSetConfig {
760 fn into_configs(self) -> SystemSetConfigs {
761 SystemSetConfigs::NodeConfig(self)
762 }
763}
764
765macro_rules! impl_system_set_collection {
766 ($(#[$meta:meta])* $($set: ident),*) => {
767 $(#[$meta])*
768 impl<$($set: IntoSystemSetConfigs),*> IntoSystemSetConfigs for ($($set,)*)
769 {
770 #[allow(non_snake_case)]
771 fn into_configs(self) -> SystemSetConfigs {
772 let ($($set,)*) = self;
773 SystemSetConfigs::Configs {
774 configs: vec![$($set.into_configs(),)*],
775 collective_conditions: Vec::new(),
776 chained: Chain::No,
777 }
778 }
779 }
780 }
781}
782
783all_tuples!(
784 #[doc(fake_variadic)]
785 impl_system_set_collection,
786 1,
787 20,
788 S
789);