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);