bevy_ecs/schedule/
node.rs

1use alloc::{boxed::Box, collections::BTreeSet, string::String, vec::Vec};
2use core::{
3    any::TypeId,
4    fmt::{self, Debug},
5    ops::{Deref, Index, IndexMut, Range},
6};
7
8use bevy_platform::collections::{HashMap, HashSet};
9use bevy_utils::prelude::DebugName;
10use slotmap::{new_key_type, Key, KeyData, SecondaryMap, SlotMap};
11use thiserror::Error;
12
13use crate::{
14    change_detection::{CheckChangeTicks, Tick},
15    component::{ComponentId, Components},
16    prelude::{SystemIn, SystemSet},
17    query::{AccessConflicts, FilteredAccessSet},
18    schedule::{
19        graph::{
20            DagAnalysis, DagGroups, DiGraph,
21            Direction::{self, Incoming, Outgoing},
22            GraphNodeId, UnGraph,
23        },
24        BoxedCondition, InternedSystemSet, ScheduleGraph,
25    },
26    storage::SparseSetIndex,
27    system::{
28        ReadOnlySystem, RunSystemError, ScheduleSystem, System, SystemParamValidationError,
29        SystemStateFlags,
30    },
31    world::{unsafe_world_cell::UnsafeWorldCell, DeferredWorld, World},
32};
33
34/// A [`SystemWithAccess`] stored in a [`ScheduleGraph`].
35pub(crate) struct SystemNode {
36    pub(crate) inner: Option<SystemWithAccess>,
37}
38
39/// A [`ScheduleSystem`] stored alongside the access returned from [`System::initialize`].
40pub struct SystemWithAccess {
41    /// The system itself.
42    pub system: ScheduleSystem,
43    /// The access returned by [`System::initialize`].
44    /// This will be empty if the system has not been initialized yet.
45    pub access: FilteredAccessSet,
46}
47
48impl SystemWithAccess {
49    /// Constructs a new [`SystemWithAccess`] from a [`ScheduleSystem`].
50    /// The `access` will initially be empty.
51    pub fn new(system: ScheduleSystem) -> Self {
52        Self {
53            system,
54            access: FilteredAccessSet::new(),
55        }
56    }
57}
58
59impl System for SystemWithAccess {
60    type In = ();
61    type Out = ();
62
63    #[inline]
64    fn name(&self) -> DebugName {
65        self.system.name()
66    }
67
68    #[inline]
69    fn type_id(&self) -> TypeId {
70        self.system.type_id()
71    }
72
73    #[inline]
74    fn flags(&self) -> SystemStateFlags {
75        self.system.flags()
76    }
77
78    #[inline]
79    unsafe fn run_unsafe(
80        &mut self,
81        input: SystemIn<'_, Self>,
82        world: UnsafeWorldCell,
83    ) -> Result<Self::Out, RunSystemError> {
84        // SAFETY: Caller ensures the same safety requirements.
85        unsafe { self.system.run_unsafe(input, world) }
86    }
87
88    #[cfg(feature = "hotpatching")]
89    #[inline]
90    fn refresh_hotpatch(&mut self) {
91        self.system.refresh_hotpatch();
92    }
93
94    #[inline]
95    fn apply_deferred(&mut self, world: &mut World) {
96        self.system.apply_deferred(world);
97    }
98
99    #[inline]
100    fn queue_deferred(&mut self, world: DeferredWorld) {
101        self.system.queue_deferred(world);
102    }
103
104    #[inline]
105    unsafe fn validate_param_unsafe(
106        &mut self,
107        world: UnsafeWorldCell,
108    ) -> Result<(), SystemParamValidationError> {
109        // SAFETY: Caller ensures the same safety requirements.
110        unsafe { self.system.validate_param_unsafe(world) }
111    }
112
113    #[inline]
114    fn initialize(&mut self, world: &mut World) -> FilteredAccessSet {
115        self.system.initialize(world)
116    }
117
118    #[inline]
119    fn check_change_tick(&mut self, check: CheckChangeTicks) {
120        self.system.check_change_tick(check);
121    }
122
123    #[inline]
124    fn default_system_sets(&self) -> Vec<InternedSystemSet> {
125        self.system.default_system_sets()
126    }
127
128    #[inline]
129    fn get_last_run(&self) -> Tick {
130        self.system.get_last_run()
131    }
132
133    #[inline]
134    fn set_last_run(&mut self, last_run: Tick) {
135        self.system.set_last_run(last_run);
136    }
137}
138
139/// A [`BoxedCondition`] stored alongside the access returned from [`System::initialize`].
140pub struct ConditionWithAccess {
141    /// The condition itself.
142    pub condition: BoxedCondition,
143    /// The access returned by [`System::initialize`].
144    /// This will be empty if the system has not been initialized yet.
145    pub access: FilteredAccessSet,
146}
147
148impl ConditionWithAccess {
149    /// Constructs a new [`ConditionWithAccess`] from a [`BoxedCondition`].
150    /// The `access` will initially be empty.
151    pub const fn new(condition: BoxedCondition) -> Self {
152        Self {
153            condition,
154            access: FilteredAccessSet::new(),
155        }
156    }
157}
158
159impl System for ConditionWithAccess {
160    type In = ();
161    type Out = bool;
162
163    #[inline]
164    fn name(&self) -> DebugName {
165        self.condition.name()
166    }
167
168    #[inline]
169    fn type_id(&self) -> TypeId {
170        self.condition.type_id()
171    }
172
173    #[inline]
174    fn flags(&self) -> SystemStateFlags {
175        self.condition.flags()
176    }
177
178    #[inline]
179    unsafe fn run_unsafe(
180        &mut self,
181        input: SystemIn<'_, Self>,
182        world: UnsafeWorldCell,
183    ) -> Result<Self::Out, RunSystemError> {
184        // SAFETY: Caller ensures the same safety requirements.
185        unsafe { self.condition.run_unsafe(input, world) }
186    }
187
188    #[cfg(feature = "hotpatching")]
189    #[inline]
190    fn refresh_hotpatch(&mut self) {
191        self.condition.refresh_hotpatch();
192    }
193
194    #[inline]
195    fn apply_deferred(&mut self, world: &mut World) {
196        self.condition.apply_deferred(world);
197    }
198
199    #[inline]
200    fn queue_deferred(&mut self, world: DeferredWorld) {
201        self.condition.queue_deferred(world);
202    }
203
204    #[inline]
205    unsafe fn validate_param_unsafe(
206        &mut self,
207        world: UnsafeWorldCell,
208    ) -> Result<(), SystemParamValidationError> {
209        // SAFETY: Caller ensures the same safety requirements.
210        unsafe { self.condition.validate_param_unsafe(world) }
211    }
212
213    #[inline]
214    fn initialize(&mut self, world: &mut World) -> FilteredAccessSet {
215        self.condition.initialize(world)
216    }
217
218    #[inline]
219    fn check_change_tick(&mut self, check: CheckChangeTicks) {
220        self.condition.check_change_tick(check);
221    }
222
223    #[inline]
224    fn default_system_sets(&self) -> Vec<InternedSystemSet> {
225        self.condition.default_system_sets()
226    }
227
228    #[inline]
229    fn get_last_run(&self) -> Tick {
230        self.condition.get_last_run()
231    }
232
233    #[inline]
234    fn set_last_run(&mut self, last_run: Tick) {
235        self.condition.set_last_run(last_run);
236    }
237}
238
239impl SystemNode {
240    /// Create a new [`SystemNode`]
241    pub fn new(system: ScheduleSystem) -> Self {
242        Self {
243            inner: Some(SystemWithAccess::new(system)),
244        }
245    }
246
247    /// Obtain a reference to the [`SystemWithAccess`] represented by this node.
248    pub fn get(&self) -> Option<&SystemWithAccess> {
249        self.inner.as_ref()
250    }
251
252    /// Obtain a mutable reference to the [`SystemWithAccess`] represented by this node.
253    pub fn get_mut(&mut self) -> Option<&mut SystemWithAccess> {
254        self.inner.as_mut()
255    }
256}
257
258new_key_type! {
259    /// A unique identifier for a system in a [`ScheduleGraph`].
260    pub struct SystemKey;
261    /// A unique identifier for a system set in a [`ScheduleGraph`].
262    pub struct SystemSetKey;
263}
264
265impl GraphNodeId for SystemKey {
266    type Adjacent = (SystemKey, Direction);
267    type Edge = (SystemKey, SystemKey);
268
269    fn kind(&self) -> &'static str {
270        "system"
271    }
272}
273
274impl GraphNodeId for SystemSetKey {
275    type Adjacent = (SystemSetKey, Direction);
276    type Edge = (SystemSetKey, SystemSetKey);
277
278    fn kind(&self) -> &'static str {
279        "system set"
280    }
281}
282
283impl TryFrom<NodeId> for SystemKey {
284    type Error = SystemSetKey;
285
286    fn try_from(value: NodeId) -> Result<Self, Self::Error> {
287        match value {
288            NodeId::System(key) => Ok(key),
289            NodeId::Set(key) => Err(key),
290        }
291    }
292}
293
294impl TryFrom<NodeId> for SystemSetKey {
295    type Error = SystemKey;
296
297    fn try_from(value: NodeId) -> Result<Self, Self::Error> {
298        match value {
299            NodeId::System(key) => Err(key),
300            NodeId::Set(key) => Ok(key),
301        }
302    }
303}
304
305/// Unique identifier for a system or system set stored in a [`ScheduleGraph`].
306///
307/// [`ScheduleGraph`]: crate::schedule::ScheduleGraph
308#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord)]
309pub enum NodeId {
310    /// Identifier for a system.
311    System(SystemKey),
312    /// Identifier for a system set.
313    Set(SystemSetKey),
314}
315
316impl NodeId {
317    /// Returns `true` if the identified node is a system.
318    pub const fn is_system(&self) -> bool {
319        matches!(self, NodeId::System(_))
320    }
321
322    /// Returns `true` if the identified node is a system set.
323    pub const fn is_set(&self) -> bool {
324        matches!(self, NodeId::Set(_))
325    }
326
327    /// Returns the system key if the node is a system, otherwise `None`.
328    pub const fn as_system(&self) -> Option<SystemKey> {
329        match self {
330            NodeId::System(system) => Some(*system),
331            NodeId::Set(_) => None,
332        }
333    }
334
335    /// Returns the system set key if the node is a system set, otherwise `None`.
336    pub const fn as_set(&self) -> Option<SystemSetKey> {
337        match self {
338            NodeId::System(_) => None,
339            NodeId::Set(set) => Some(*set),
340        }
341    }
342}
343
344impl GraphNodeId for NodeId {
345    type Adjacent = CompactNodeIdAndDirection;
346    type Edge = CompactNodeIdPair;
347
348    fn kind(&self) -> &'static str {
349        match self {
350            NodeId::System(n) => n.kind(),
351            NodeId::Set(n) => n.kind(),
352        }
353    }
354}
355
356impl From<SystemKey> for NodeId {
357    fn from(system: SystemKey) -> Self {
358        NodeId::System(system)
359    }
360}
361
362impl From<SystemSetKey> for NodeId {
363    fn from(set: SystemSetKey) -> Self {
364        NodeId::Set(set)
365    }
366}
367
368/// Compact storage of a [`NodeId`] and a [`Direction`].
369#[derive(Clone, Copy)]
370pub struct CompactNodeIdAndDirection {
371    key: KeyData,
372    is_system: bool,
373    direction: Direction,
374}
375
376impl Debug for CompactNodeIdAndDirection {
377    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
378        let tuple: (_, _) = (*self).into();
379        tuple.fmt(f)
380    }
381}
382
383impl From<(NodeId, Direction)> for CompactNodeIdAndDirection {
384    fn from((id, direction): (NodeId, Direction)) -> Self {
385        let key = match id {
386            NodeId::System(key) => key.data(),
387            NodeId::Set(key) => key.data(),
388        };
389        let is_system = id.is_system();
390
391        Self {
392            key,
393            is_system,
394            direction,
395        }
396    }
397}
398
399impl From<CompactNodeIdAndDirection> for (NodeId, Direction) {
400    fn from(value: CompactNodeIdAndDirection) -> Self {
401        let node = match value.is_system {
402            true => NodeId::System(value.key.into()),
403            false => NodeId::Set(value.key.into()),
404        };
405
406        (node, value.direction)
407    }
408}
409
410/// Compact storage of a [`NodeId`] pair.
411#[derive(Clone, Copy, Hash, PartialEq, Eq)]
412pub struct CompactNodeIdPair {
413    key_a: KeyData,
414    key_b: KeyData,
415    is_system_a: bool,
416    is_system_b: bool,
417}
418
419impl Debug for CompactNodeIdPair {
420    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
421        let tuple: (_, _) = (*self).into();
422        tuple.fmt(f)
423    }
424}
425
426impl From<(NodeId, NodeId)> for CompactNodeIdPair {
427    fn from((a, b): (NodeId, NodeId)) -> Self {
428        let key_a = match a {
429            NodeId::System(index) => index.data(),
430            NodeId::Set(index) => index.data(),
431        };
432        let is_system_a = a.is_system();
433
434        let key_b = match b {
435            NodeId::System(index) => index.data(),
436            NodeId::Set(index) => index.data(),
437        };
438        let is_system_b = b.is_system();
439
440        Self {
441            key_a,
442            key_b,
443            is_system_a,
444            is_system_b,
445        }
446    }
447}
448
449impl From<CompactNodeIdPair> for (NodeId, NodeId) {
450    fn from(value: CompactNodeIdPair) -> Self {
451        let a = match value.is_system_a {
452            true => NodeId::System(value.key_a.into()),
453            false => NodeId::Set(value.key_a.into()),
454        };
455
456        let b = match value.is_system_b {
457            true => NodeId::System(value.key_b.into()),
458            false => NodeId::Set(value.key_b.into()),
459        };
460
461        (a, b)
462    }
463}
464
465/// Container for systems in a schedule.
466#[derive(Default)]
467pub struct Systems {
468    /// List of systems in the schedule.
469    nodes: SlotMap<SystemKey, SystemNode>,
470    /// List of conditions for each system, in the same order as `nodes`.
471    conditions: SecondaryMap<SystemKey, Vec<ConditionWithAccess>>,
472    /// Systems and their conditions that have not been initialized yet.
473    uninit: Vec<SystemKey>,
474}
475
476impl Systems {
477    /// Returns the number of systems in this container.
478    pub fn len(&self) -> usize {
479        self.nodes.len()
480    }
481
482    /// Returns `true` if this container is empty.
483    pub fn is_empty(&self) -> bool {
484        self.nodes.is_empty()
485    }
486
487    /// Returns a reference to the system with the given key, if it exists.
488    pub fn get(&self, key: SystemKey) -> Option<&SystemWithAccess> {
489        self.nodes.get(key).and_then(|node| node.get())
490    }
491
492    /// Returns a mutable reference to the system with the given key, if it exists.
493    pub fn get_mut(&mut self, key: SystemKey) -> Option<&mut SystemWithAccess> {
494        self.nodes.get_mut(key).and_then(|node| node.get_mut())
495    }
496
497    /// Returns a mutable reference to the system with the given key. Will return
498    /// `None` if the key does not exist.
499    pub(crate) fn node_mut(&mut self, key: SystemKey) -> Option<&mut SystemNode> {
500        self.nodes.get_mut(key)
501    }
502
503    /// Returns `true` if the system with the given key has conditions.
504    pub fn has_conditions(&self, key: SystemKey) -> bool {
505        self.conditions
506            .get(key)
507            .is_some_and(|conditions| !conditions.is_empty())
508    }
509
510    /// Returns a reference to the conditions for the system with the given key, if it exists.
511    pub fn get_conditions(&self, key: SystemKey) -> Option<&[ConditionWithAccess]> {
512        self.conditions.get(key).map(Vec::as_slice)
513    }
514
515    /// Returns a mutable reference to the conditions for the system with the given key, if it exists.
516    pub fn get_conditions_mut(&mut self, key: SystemKey) -> Option<&mut Vec<ConditionWithAccess>> {
517        self.conditions.get_mut(key)
518    }
519
520    /// Returns an iterator over all systems and their conditions in this
521    /// container.
522    pub fn iter(
523        &self,
524    ) -> impl Iterator<Item = (SystemKey, &ScheduleSystem, &[ConditionWithAccess])> + '_ {
525        self.nodes.iter().filter_map(|(key, node)| {
526            let system = &node.get()?.system;
527            let conditions = self
528                .conditions
529                .get(key)
530                .map(Vec::as_slice)
531                .unwrap_or_default();
532            Some((key, system, conditions))
533        })
534    }
535
536    /// Inserts a new system into the container, along with its conditions,
537    /// and queues it to be initialized later in [`Systems::initialize`].
538    ///
539    /// We have to defer initialization of systems in the container until we have
540    /// `&mut World` access, so we store these in a list until
541    /// [`Systems::initialize`] is called. This is usually done upon the first
542    /// run of the schedule.
543    pub fn insert(
544        &mut self,
545        system: ScheduleSystem,
546        conditions: Vec<Box<dyn ReadOnlySystem<In = (), Out = bool>>>,
547    ) -> SystemKey {
548        let key = self.nodes.insert(SystemNode::new(system));
549        self.conditions.insert(
550            key,
551            conditions
552                .into_iter()
553                .map(ConditionWithAccess::new)
554                .collect(),
555        );
556        self.uninit.push(key);
557        key
558    }
559
560    /// Remove a system with [`SystemKey`]
561    pub(crate) fn remove(&mut self, key: SystemKey) -> bool {
562        let mut found = false;
563        if self.nodes.remove(key).is_some() {
564            found = true;
565        }
566
567        if self.conditions.remove(key).is_some() {
568            found = true;
569        }
570
571        if let Some(index) = self.uninit.iter().position(|value| *value == key) {
572            self.uninit.remove(index);
573            found = true;
574        }
575
576        found
577    }
578
579    /// Returns `true` if all systems in this container have been initialized.
580    pub fn is_initialized(&self) -> bool {
581        self.uninit.is_empty()
582    }
583
584    /// Initializes all systems and their conditions that have not been
585    /// initialized yet.
586    pub fn initialize(&mut self, world: &mut World) {
587        for key in self.uninit.drain(..) {
588            let Some(system) = self.nodes.get_mut(key).and_then(|node| node.get_mut()) else {
589                continue;
590            };
591            system.access = system.system.initialize(world);
592            let Some(conditions) = self.conditions.get_mut(key) else {
593                continue;
594            };
595            for condition in conditions {
596                condition.access = condition.condition.initialize(world);
597            }
598        }
599    }
600
601    /// Calculates the list of systems that conflict with each other based on
602    /// their access patterns.
603    ///
604    /// If the `Box<[ComponentId]>` is empty for a given pair of systems, then the
605    /// systems conflict on [`World`] access in general (e.g. one of them is
606    /// exclusive, or both systems have `Query<EntityMut>`).
607    pub fn get_conflicting_systems(
608        &self,
609        flat_dependency_analysis: &DagAnalysis<SystemKey>,
610        flat_ambiguous_with: &UnGraph<SystemKey>,
611        ambiguous_with_all: &HashSet<NodeId>,
612        ignored_ambiguities: &BTreeSet<ComponentId>,
613    ) -> ConflictingSystems {
614        let mut conflicting_systems: Vec<(_, _, Box<[_]>)> = Vec::new();
615        for &(a, b) in flat_dependency_analysis.disconnected() {
616            if flat_ambiguous_with.contains_edge(a, b)
617                || ambiguous_with_all.contains(&NodeId::System(a))
618                || ambiguous_with_all.contains(&NodeId::System(b))
619            {
620                continue;
621            }
622
623            let system_a = &self[a];
624            let system_b = &self[b];
625            if system_a.is_exclusive() || system_b.is_exclusive() {
626                conflicting_systems.push((a, b, Box::new([])));
627            } else {
628                let access_a = &system_a.access;
629                let access_b = &system_b.access;
630                if !access_a.is_compatible(access_b) {
631                    match access_a.get_conflicts(access_b) {
632                        AccessConflicts::Individual(conflicts) => {
633                            let conflicts: Box<[_]> = conflicts
634                                .ones()
635                                .map(ComponentId::get_sparse_set_index)
636                                .filter(|id| !ignored_ambiguities.contains(id))
637                                .collect();
638                            if !conflicts.is_empty() {
639                                conflicting_systems.push((a, b, conflicts));
640                            }
641                        }
642                        AccessConflicts::All => {
643                            // there is no specific component conflicting, but the systems are overall incompatible
644                            // for example 2 systems with `Query<EntityMut>`
645                            conflicting_systems.push((a, b, Box::new([])));
646                        }
647                    }
648                }
649            }
650        }
651
652        ConflictingSystems(conflicting_systems)
653    }
654}
655
656impl Index<SystemKey> for Systems {
657    type Output = SystemWithAccess;
658
659    #[track_caller]
660    fn index(&self, key: SystemKey) -> &Self::Output {
661        self.get(key)
662            .unwrap_or_else(|| panic!("System with key {:?} does not exist in the schedule", key))
663    }
664}
665
666impl IndexMut<SystemKey> for Systems {
667    #[track_caller]
668    fn index_mut(&mut self, key: SystemKey) -> &mut Self::Output {
669        self.get_mut(key)
670            .unwrap_or_else(|| panic!("System with key {:?} does not exist in the schedule", key))
671    }
672}
673
674/// Pairs of systems that conflict with each other along with the components
675/// they conflict on, which prevents them from running in parallel. If the
676/// component list is empty, the systems conflict on [`World`] access in general
677/// (e.g. one of them is exclusive, or both systems have `Query<EntityMut>`).
678#[derive(Clone, Debug, Default)]
679pub struct ConflictingSystems(pub Vec<(SystemKey, SystemKey, Box<[ComponentId]>)>);
680
681impl ConflictingSystems {
682    /// Checks if there are any conflicting systems, returning [`Ok`] if there
683    /// are none, or an [`AmbiguousSystemConflictsWarning`] if there are.
684    pub fn check_if_not_empty(&self) -> Result<(), AmbiguousSystemConflictsWarning> {
685        if self.0.is_empty() {
686            Ok(())
687        } else {
688            Err(AmbiguousSystemConflictsWarning(self.clone()))
689        }
690    }
691
692    /// Converts the conflicting systems into an iterator of their system names
693    /// and the names of the components they conflict on.
694    pub fn to_string(
695        &self,
696        graph: &ScheduleGraph,
697        components: &Components,
698    ) -> impl Iterator<Item = (String, String, Box<[DebugName]>)> {
699        self.iter().map(move |(system_a, system_b, conflicts)| {
700            let name_a = graph.get_node_name(&NodeId::System(*system_a));
701            let name_b = graph.get_node_name(&NodeId::System(*system_b));
702
703            let conflict_names: Box<[_]> = conflicts
704                .iter()
705                .map(|id| components.get_name(*id).unwrap())
706                .collect();
707
708            (name_a, name_b, conflict_names)
709        })
710    }
711}
712
713impl Deref for ConflictingSystems {
714    type Target = Vec<(SystemKey, SystemKey, Box<[ComponentId]>)>;
715
716    fn deref(&self) -> &Self::Target {
717        &self.0
718    }
719}
720
721/// Error returned when there are ambiguous system conflicts detected.
722#[derive(Error, Debug)]
723#[error("Systems with conflicting access have indeterminate run order: {:?}", .0.0)]
724pub struct AmbiguousSystemConflictsWarning(pub ConflictingSystems);
725
726/// Container for system sets in a schedule.
727#[derive(Default)]
728pub struct SystemSets {
729    /// List of system sets in the schedule.
730    sets: SlotMap<SystemSetKey, InternedSystemSet>,
731    /// List of conditions for each system set, in the same order as `sets`.
732    conditions: SecondaryMap<SystemSetKey, Vec<ConditionWithAccess>>,
733    /// Map from system sets to their keys.
734    ids: HashMap<InternedSystemSet, SystemSetKey>,
735    /// System sets that have not been initialized yet.
736    uninit: Vec<UninitializedSet>,
737}
738
739/// A system set's conditions that have not been initialized yet.
740struct UninitializedSet {
741    key: SystemSetKey,
742    /// The range of indices in [`SystemSets::conditions`] that correspond
743    /// to conditions that have not been initialized yet.
744    ///
745    /// [`SystemSets::conditions`] for a given set may be appended to
746    /// multiple times (e.g. when `configure_sets` is called multiple with
747    /// the same set), so we need to track which conditions in that list
748    /// are newly added and not yet initialized.
749    ///
750    /// Systems don't need this tracking because each `add_systems` call
751    /// creates separate nodes in the graph with their own conditions,
752    /// so all conditions are initialized together.
753    uninitialized_conditions: Range<usize>,
754}
755
756impl SystemSets {
757    /// Returns the number of system sets in this container.
758    pub fn len(&self) -> usize {
759        self.sets.len()
760    }
761
762    /// Returns `true` if this container is empty.
763    pub fn is_empty(&self) -> bool {
764        self.sets.is_empty()
765    }
766
767    /// Returns `true` if the given set is present in this container.
768    pub fn contains(&self, set: impl SystemSet) -> bool {
769        self.ids.contains_key(&set.intern())
770    }
771
772    /// Returns a reference to the system set with the given key, if it exists.
773    pub fn get(&self, key: SystemSetKey) -> Option<&dyn SystemSet> {
774        self.sets.get(key).map(|set| &**set)
775    }
776
777    /// Returns the key for the given system set, returns None if it does not exist.
778    pub fn get_key(&self, set: InternedSystemSet) -> Option<SystemSetKey> {
779        self.ids.get(&set).copied()
780    }
781
782    /// Returns the key for the given system set, inserting it into this
783    /// container if it does not already exist.
784    pub fn get_key_or_insert(&mut self, set: InternedSystemSet) -> SystemSetKey {
785        *self.ids.entry(set).or_insert_with(|| {
786            let key = self.sets.insert(set);
787            self.conditions.insert(key, Vec::new());
788            key
789        })
790    }
791
792    /// Returns `true` if the system set with the given key has conditions.
793    pub fn has_conditions(&self, key: SystemSetKey) -> bool {
794        self.conditions
795            .get(key)
796            .is_some_and(|conditions| !conditions.is_empty())
797    }
798
799    /// Returns a reference to the conditions for the system set with the given
800    /// key, if it exists.
801    pub fn get_conditions(&self, key: SystemSetKey) -> Option<&[ConditionWithAccess]> {
802        self.conditions.get(key).map(Vec::as_slice)
803    }
804
805    /// Returns a mutable reference to the conditions for the system set with
806    /// the given key, if it exists.
807    pub fn get_conditions_mut(
808        &mut self,
809        key: SystemSetKey,
810    ) -> Option<&mut Vec<ConditionWithAccess>> {
811        self.conditions.get_mut(key)
812    }
813
814    /// Returns an iterator over all system sets in this container, along with
815    /// their conditions.
816    pub fn iter(
817        &self,
818    ) -> impl Iterator<Item = (SystemSetKey, &dyn SystemSet, &[ConditionWithAccess])> {
819        self.sets.iter().filter_map(|(key, set)| {
820            let conditions = self.conditions.get(key)?.as_slice();
821            Some((key, &**set, conditions))
822        })
823    }
824
825    /// Inserts conditions for a system set into the container, and queues the
826    /// newly added conditions to be initialized later in [`SystemSets::initialize`].
827    ///
828    /// If the set was not already present in the container, it is added automatically.
829    ///
830    /// We have to defer initialization of system set conditions in the container
831    /// until we have `&mut World` access, so we store these in a list until
832    /// [`SystemSets::initialize`] is called. This is usually done upon the
833    /// first run of the schedule.
834    pub fn insert(
835        &mut self,
836        set: InternedSystemSet,
837        new_conditions: Vec<Box<dyn ReadOnlySystem<In = (), Out = bool>>>,
838    ) -> SystemSetKey {
839        let key = self.get_key_or_insert(set);
840        if !new_conditions.is_empty() {
841            let current_conditions = &mut self.conditions[key];
842            let start = current_conditions.len();
843            self.uninit.push(UninitializedSet {
844                key,
845                uninitialized_conditions: start..(start + new_conditions.len()),
846            });
847            current_conditions.extend(new_conditions.into_iter().map(ConditionWithAccess::new));
848        }
849        key
850    }
851
852    /// Remove a set with a [`SystemSetKey`]
853    pub(crate) fn remove(&mut self, key: SystemSetKey) -> bool {
854        self.sets.remove(key);
855        self.conditions.remove(key);
856        self.uninit.retain(|uninit| uninit.key != key);
857        true
858    }
859
860    /// Returns `true` if all system sets' conditions in this container have
861    /// been initialized.
862    pub fn is_initialized(&self) -> bool {
863        self.uninit.is_empty()
864    }
865
866    /// Initializes all system sets' conditions that have not been
867    /// initialized yet. Because a system set's conditions may be appended to
868    /// multiple times, we track which conditions were added since the last
869    /// initialization and only initialize those.
870    pub fn initialize(&mut self, world: &mut World) {
871        for uninit in self.uninit.drain(..) {
872            let Some(conditions) = self.conditions.get_mut(uninit.key) else {
873                continue;
874            };
875            for condition in &mut conditions[uninit.uninitialized_conditions] {
876                condition.access = condition.initialize(world);
877            }
878        }
879    }
880
881    /// Ensures that there are no edges to system-type sets that have multiple
882    /// instances.
883    pub fn check_type_set_ambiguity(
884        &self,
885        set_systems: &DagGroups<SystemSetKey, SystemKey>,
886        ambiguous_with: &UnGraph<NodeId>,
887        dependency: &DiGraph<NodeId>,
888    ) -> Result<(), SystemTypeSetAmbiguityError> {
889        for (&key, systems) in set_systems.iter() {
890            let set = &self[key];
891            if set.system_type().is_some() {
892                let instances = systems.len();
893                let ambiguous_with = ambiguous_with.edges(NodeId::Set(key));
894                let before = dependency.edges_directed(NodeId::Set(key), Incoming);
895                let after = dependency.edges_directed(NodeId::Set(key), Outgoing);
896                let relations = before.count() + after.count() + ambiguous_with.count();
897                if instances > 1 && relations > 0 {
898                    return Err(SystemTypeSetAmbiguityError(key));
899                }
900            }
901        }
902        Ok(())
903    }
904}
905
906impl Index<SystemSetKey> for SystemSets {
907    type Output = dyn SystemSet;
908
909    #[track_caller]
910    fn index(&self, key: SystemSetKey) -> &Self::Output {
911        self.get(key).unwrap_or_else(|| {
912            panic!(
913                "System set with key {:?} does not exist in the schedule",
914                key
915            )
916        })
917    }
918}
919
920/// Error returned when calling [`SystemSets::check_type_set_ambiguity`].
921#[derive(Error, Debug)]
922#[error("Tried to order against `{0:?}` in a schedule that has more than one `{0:?}` instance. `{0:?}` is a `SystemTypeSet` and cannot be used for ordering if ambiguous. Use a different set without this restriction.")]
923pub struct SystemTypeSetAmbiguityError(pub SystemSetKey);
924
925#[cfg(test)]
926mod tests {
927    use alloc::{boxed::Box, vec};
928
929    use crate::{
930        prelude::SystemSet,
931        schedule::{SystemSets, Systems},
932        system::IntoSystem,
933        world::World,
934    };
935
936    #[derive(SystemSet, Clone, Copy, PartialEq, Eq, Debug, Hash)]
937    pub struct TestSet;
938
939    #[test]
940    fn systems() {
941        fn empty_system() {}
942
943        let mut systems = Systems::default();
944        assert!(systems.is_empty());
945        assert_eq!(systems.len(), 0);
946
947        let system = Box::new(IntoSystem::into_system(empty_system));
948        let key = systems.insert(system, vec![]);
949
950        assert!(!systems.is_empty());
951        assert_eq!(systems.len(), 1);
952        assert!(systems.get(key).is_some());
953        assert!(systems.get_conditions(key).is_some());
954        assert!(systems.get_conditions(key).unwrap().is_empty());
955        assert!(systems.get_mut(key).is_some());
956        assert!(!systems.is_initialized());
957        assert!(systems.iter().next().is_some());
958
959        let mut world = World::new();
960        systems.initialize(&mut world);
961        assert!(systems.is_initialized());
962    }
963
964    #[test]
965    fn system_sets() {
966        fn always_true() -> bool {
967            true
968        }
969
970        let mut sets = SystemSets::default();
971        assert!(sets.is_empty());
972        assert_eq!(sets.len(), 0);
973
974        let condition = Box::new(IntoSystem::into_system(always_true));
975        let key = sets.insert(TestSet.intern(), vec![condition]);
976
977        assert!(!sets.is_empty());
978        assert_eq!(sets.len(), 1);
979        assert!(sets.get(key).is_some());
980        assert!(sets.get_conditions(key).is_some());
981        assert!(!sets.get_conditions(key).unwrap().is_empty());
982        assert!(!sets.is_initialized());
983        assert!(sets.iter().next().is_some());
984
985        let mut world = World::new();
986        sets.initialize(&mut world);
987        assert!(sets.is_initialized());
988    }
989}