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
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
51/// Stores configuration for a single generic node (a system or a system set)
52///
53/// The configuration includes the node itself, scheduling metadata
54/// (hierarchy: in which sets is the node contained,
55/// dependencies: before/after which other nodes should this node run)
56/// and the run conditions associated with this node.
57pub struct NodeConfig<T> {
58    pub(crate) node: T,
59    /// Hierarchy and dependency metadata for this node
60    pub(crate) graph_info: GraphInfo,
61    pub(crate) conditions: Vec<BoxedCondition>,
62}
63
64/// Stores configuration for a single system.
65pub type SystemConfig = NodeConfig<BoxedSystem>;
66
67/// A collections of generic [`NodeConfig`]s.
68pub enum NodeConfigs<T> {
69    /// Configuration for a single node.
70    NodeConfig(NodeConfig<T>),
71    /// Configuration for a tuple of nested `Configs` instances.
72    Configs {
73        /// Configuration for each element of the tuple.
74        configs: Vec<NodeConfigs<T>>,
75        /// Run conditions applied to everything in the tuple.
76        collective_conditions: Vec<BoxedCondition>,
77        /// See [`Chain`] for usage.
78        chained: Chain,
79    },
80}
81
82/// A collection of [`SystemConfig`].
83pub type SystemConfigs = NodeConfigs<BoxedSystem>;
84
85impl SystemConfigs {
86    fn new_system(system: BoxedSystem) -> Self {
87        // include system in its default sets
88        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    /// Adds a new boxed system set to the systems.
102    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    /// Adds a new boxed run condition to the systems.
219    ///
220    /// This is useful if you have a run condition whose concrete type is unknown.
221    /// Prefer `run_if` for run conditions whose type is known at compile time.
222    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(_) => { /* no op */ }
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(_) => { /* no op */ }
249            Self::Configs { chained, .. } => {
250                *chained = Chain::YesIgnoreDeferred;
251            }
252        }
253        self
254    }
255}
256
257/// Types that can convert into a [`SystemConfigs`].
258///
259/// This trait is implemented for "systems" (functions whose arguments all implement
260/// [`SystemParam`](crate::system::SystemParam)), or tuples thereof.
261/// It is a common entry point for system configurations.
262///
263/// # Examples
264///
265/// ```
266/// # use bevy_ecs::schedule::IntoSystemConfigs;
267/// # struct AppMock;
268/// # struct Update;
269/// # impl AppMock {
270/// #     pub fn add_systems<M>(
271/// #         &mut self,
272/// #         schedule: Update,
273/// #         systems: impl IntoSystemConfigs<M>,
274/// #    ) -> &mut Self { self }
275/// # }
276/// # let mut app = AppMock;
277///
278/// fn handle_input() {}
279///
280/// fn update_camera() {}
281/// fn update_character() {}
282///
283/// app.add_systems(
284///     Update,
285///     (
286///         handle_input,
287///         (update_camera, update_character).after(handle_input)
288///     )
289/// );
290/// ```
291#[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    /// Convert into a [`SystemConfigs`].
300    fn into_configs(self) -> SystemConfigs;
301
302    /// Add these systems to the provided `set`.
303    #[track_caller]
304    fn in_set(self, set: impl SystemSet) -> SystemConfigs {
305        self.into_configs().in_set(set)
306    }
307
308    /// Runs before all systems in `set`. If `self` has any systems that produce [`Commands`](crate::system::Commands)
309    /// or other [`Deferred`](crate::system::Deferred) operations, all systems in `set` will see their effect.
310    ///
311    /// If automatically inserting [`apply_deferred`](crate::schedule::apply_deferred) like
312    /// this isn't desired, use [`before_ignore_deferred`](Self::before_ignore_deferred) instead.
313    ///
314    /// Note: The given set is not implicitly added to the schedule when this system set is added.
315    /// It is safe, but no dependencies will be created.
316    fn before<M>(self, set: impl IntoSystemSet<M>) -> SystemConfigs {
317        self.into_configs().before(set)
318    }
319
320    /// Run after all systems in `set`. If `set` has any systems that produce [`Commands`](crate::system::Commands)
321    /// or other [`Deferred`](crate::system::Deferred) operations, all systems in `self` will see their effect.
322    ///
323    /// If automatically inserting [`apply_deferred`](crate::schedule::apply_deferred) like
324    /// this isn't desired, use [`after_ignore_deferred`](Self::after_ignore_deferred) instead.
325    ///
326    /// Note: The given set is not implicitly added to the schedule when this system set is added.
327    /// It is safe, but no dependencies will be created.
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
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
544/// A [`SystemSet`] with scheduling metadata.
545pub type SystemSetConfig = NodeConfig<InternedSystemSet>;
546
547impl SystemSetConfig {
548    #[track_caller]
549    pub(super) fn new(set: InternedSystemSet) -> Self {
550        // system type sets are automatically populated
551        // to avoid unintentionally broad changes, they cannot be configured
552        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
565/// A collection of [`SystemSetConfig`].
566pub type SystemSetConfigs = NodeConfigs<InternedSystemSet>;
567
568/// Types that can convert into a [`SystemSetConfigs`].
569#[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    /// Convert into a [`SystemSetConfigs`].
578    #[doc(hidden)]
579    fn into_configs(self) -> SystemSetConfigs;
580
581    /// Add these system sets to the provided `set`.
582    #[track_caller]
583    fn in_set(self, set: impl SystemSet) -> SystemSetConfigs {
584        self.into_configs().in_set(set)
585    }
586
587    /// Runs before all systems in `set`. If `self` has any systems that produce [`Commands`](crate::system::Commands)
588    /// or other [`Deferred`](crate::system::Deferred) operations, all systems in `set` will see their effect.
589    ///
590    /// If automatically inserting [`apply_deferred`](crate::schedule::apply_deferred) like
591    /// this isn't desired, use [`before_ignore_deferred`](Self::before_ignore_deferred) instead.
592    fn before<M>(self, set: impl IntoSystemSet<M>) -> SystemSetConfigs {
593        self.into_configs().before(set)
594    }
595
596    /// Runs before all systems in `set`. If `set` has any systems that produce [`Commands`](crate::system::Commands)
597    /// or other [`Deferred`](crate::system::Deferred) operations, all systems in `self` will see their effect.
598    ///
599    /// If automatically inserting [`apply_deferred`](crate::schedule::apply_deferred) like
600    /// this isn't desired, use [`after_ignore_deferred`](Self::after_ignore_deferred) instead.
601    fn after<M>(self, set: impl IntoSystemSet<M>) -> SystemSetConfigs {
602        self.into_configs().after(set)
603    }
604
605    /// Run before all systems in `set`.
606    ///
607    /// Unlike [`before`](Self::before), this will not cause the systems in `set` to wait for the
608    /// deferred effects of `self` to be applied.
609    fn before_ignore_deferred<M>(self, set: impl IntoSystemSet<M>) -> SystemSetConfigs {
610        self.into_configs().before_ignore_deferred(set)
611    }
612
613    /// Run after all systems in `set`.
614    ///
615    /// Unlike [`after`](Self::after), this may not see the deferred
616    /// effects of systems in `set` to be applied.
617    fn after_ignore_deferred<M>(self, set: impl IntoSystemSet<M>) -> SystemSetConfigs {
618        self.into_configs().after_ignore_deferred(set)
619    }
620
621    /// Run the systems in this set(s) only if the [`Condition`] is `true`.
622    ///
623    /// The `Condition` will be evaluated at most once (per schedule run),
624    /// the first time a system in this set(s) prepares to run.
625    fn run_if<M>(self, condition: impl Condition<M>) -> SystemSetConfigs {
626        self.into_configs().run_if(condition)
627    }
628
629    /// Suppress warnings and errors that would result from systems in these sets having ambiguities
630    /// (conflicting access but indeterminate order) with systems in `set`.
631    fn ambiguous_with<M>(self, set: impl IntoSystemSet<M>) -> SystemSetConfigs {
632        self.into_configs().ambiguous_with(set)
633    }
634
635    /// Suppress warnings and errors that would result from systems in these sets having ambiguities
636    /// (conflicting access but indeterminate order) with any other system.
637    fn ambiguous_with_all(self) -> SystemSetConfigs {
638        self.into_configs().ambiguous_with_all()
639    }
640
641    /// Treat this collection as a sequence of system sets.
642    ///
643    /// Ordering constraints will be applied between the successive elements.
644    fn chain(self) -> SystemSetConfigs {
645        self.into_configs().chain()
646    }
647
648    /// Treat this collection as a sequence of systems.
649    ///
650    /// Ordering constraints will be applied between the successive elements.
651    ///
652    /// Unlike [`chain`](Self::chain) this will **not** add [`apply_deferred`](crate::schedule::apply_deferred) on the edges.
653    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);