Skip to main content

bevy_ecs/schedule/
set.rs

1use alloc::boxed::Box;
2use bevy_utils::prelude::DebugName;
3use core::{
4    any::TypeId,
5    fmt::Debug,
6    hash::{Hash, Hasher},
7    marker::PhantomData,
8};
9
10pub use crate::label::DynEq;
11pub use bevy_ecs_macros::{ScheduleLabel, SystemSet};
12
13use crate::{
14    define_label,
15    intern::Interned,
16    system::{
17        ExclusiveSystemParamFunction, FromInput, IntoResult, IsExclusiveFunctionSystem,
18        IsFunctionSystem, SystemParamFunction,
19    },
20};
21
22#[doc = r" A strongly-typed class of labels used to identify a [`Schedule`]."]
#[doc = r""]
#[doc =
r" Each schedule in a [`World`] has a unique schedule label value, and"]
#[doc =
r" schedules can be automatically created from labels via [`Schedules::add_systems()`]."]
#[doc = r""]
#[doc = r" # Defining new schedule labels"]
#[doc = r""]
#[doc =
r" By default, you should use Bevy's premade schedule labels which implement this trait."]
#[doc =
r" If you are using [`bevy_ecs`] directly or if you need to run a group of systems outside"]
#[doc =
r" the existing schedules, you may define your own schedule labels by using"]
#[doc = r" `#[derive(ScheduleLabel)]`."]
#[doc = r""]
#[doc = r" ```"]
#[doc = r" use bevy_ecs::prelude::*;"]
#[doc = r" use bevy_ecs::schedule::ScheduleLabel;"]
#[doc = r""]
#[doc = r" // Declare a new schedule label."]
#[doc =
r" #[derive(ScheduleLabel, Clone, Debug, PartialEq, Eq, Hash, Default)]"]
#[doc = r" struct Update;"]
#[doc = r""]
#[doc = r" let mut world = World::new();"]
#[doc = r""]
#[doc =
r" // Add a system to the schedule with that label (creating it automatically)."]
#[doc = r" fn a_system_function() {}"]
#[doc =
r" world.get_resource_or_init::<Schedules>().add_systems(Update, a_system_function);"]
#[doc = r""]
#[doc = r" // Run the schedule, and therefore run the system."]
#[doc = r" world.run_schedule(Update);"]
#[doc = r" ```"]
#[doc = r""]
#[doc = r" [`Schedule`]: crate::schedule::Schedule"]
#[doc =
r" [`Schedules::add_systems()`]: crate::schedule::Schedules::add_systems"]
#[doc = r" [`World`]: crate::world::World"]
#[diagnostic::on_unimplemented(note =
"consider annotating `{Self}` with `#[derive(ScheduleLabel)]`")]
pub trait ScheduleLabel: Send + Sync + ::core::fmt::Debug +
    crate::label::DynEq + crate::label::DynHash {
    /// Clones this `
    #[doc = "ScheduleLabel"]
    ///`.
    fn dyn_clone(&self)
    -> crate::label::Box<dyn ScheduleLabel>;
    /// Returns an [`Interned`] value corresponding to `self`.
    fn intern(&self) -> crate::intern::Interned<dyn ScheduleLabel> where
        Self: Sized {
        SCHEDULE_LABEL_INTERNER.intern(self)
    }
}
#[diagnostic::do_not_recommend]
impl ScheduleLabel for crate::intern::Interned<dyn ScheduleLabel> {
    fn dyn_clone(&self) -> crate::label::Box<dyn ScheduleLabel> {
        (**self).dyn_clone()
    }
    fn intern(&self) -> Self { *self }
}
impl PartialEq for dyn ScheduleLabel {
    fn eq(&self, other: &Self) -> bool { self.dyn_eq(other) }
}
impl Eq for dyn ScheduleLabel {}
impl ::core::hash::Hash for dyn ScheduleLabel {
    fn hash<H: ::core::hash::Hasher>(&self, state: &mut H) {
        self.dyn_hash(state);
    }
}
impl crate::intern::Internable for dyn ScheduleLabel {
    fn leak(&self) -> &'static Self {
        crate::label::Box::leak(self.dyn_clone())
    }
    fn ref_eq(&self, other: &Self) -> bool {
        use ::core::ptr;
        self.type_id() == other.type_id() &&
            ptr::addr_eq(ptr::from_ref::<Self>(self),
                ptr::from_ref::<Self>(other))
    }
    fn ref_hash<H: ::core::hash::Hasher>(&self, state: &mut H) {
        use ::core::{hash::Hash, ptr};
        self.type_id().hash(state);
        ptr::from_ref::<Self>(self).cast::<()>().hash(state);
    }
}
static SCHEDULE_LABEL_INTERNER: crate::intern::Interner<dyn ScheduleLabel> =
    crate::intern::Interner::new();define_label!(
23    /// A strongly-typed class of labels used to identify a [`Schedule`].
24    ///
25    /// Each schedule in a [`World`] has a unique schedule label value, and
26    /// schedules can be automatically created from labels via [`Schedules::add_systems()`].
27    ///
28    /// # Defining new schedule labels
29    ///
30    /// By default, you should use Bevy's premade schedule labels which implement this trait.
31    /// If you are using [`bevy_ecs`] directly or if you need to run a group of systems outside
32    /// the existing schedules, you may define your own schedule labels by using
33    /// `#[derive(ScheduleLabel)]`.
34    ///
35    /// ```
36    /// use bevy_ecs::prelude::*;
37    /// use bevy_ecs::schedule::ScheduleLabel;
38    ///
39    /// // Declare a new schedule label.
40    /// #[derive(ScheduleLabel, Clone, Debug, PartialEq, Eq, Hash, Default)]
41    /// struct Update;
42    ///
43    /// let mut world = World::new();
44    ///
45    /// // Add a system to the schedule with that label (creating it automatically).
46    /// fn a_system_function() {}
47    /// world.get_resource_or_init::<Schedules>().add_systems(Update, a_system_function);
48    ///
49    /// // Run the schedule, and therefore run the system.
50    /// world.run_schedule(Update);
51    /// ```
52    ///
53    /// [`Schedule`]: crate::schedule::Schedule
54    /// [`Schedules::add_systems()`]: crate::schedule::Schedules::add_systems
55    /// [`World`]: crate::world::World
56    #[diagnostic::on_unimplemented(
57        note = "consider annotating `{Self}` with `#[derive(ScheduleLabel)]`"
58    )]
59    ScheduleLabel,
60    SCHEDULE_LABEL_INTERNER
61);
62
63#[doc =
r" System sets are tag-like labels that can be used to group systems together."]
#[doc = r""]
#[doc =
r" This allows you to share configuration (like run conditions) across multiple systems,"]
#[doc =
r" and order systems or system sets relative to conceptual groups of systems."]
#[doc =
r" To control the behavior of a system set as a whole, use [`Schedule::configure_sets`](crate::prelude::Schedule::configure_sets),"]
#[doc = r" or the method of the same name on `App`."]
#[doc = r""]
#[doc =
r" Systems can belong to any number of system sets, reflecting multiple roles or facets that they might have."]
#[doc =
r#" For example, you may want to annotate a system as "consumes input" and "applies forces","#]
#[doc =
r" and ensure that your systems are ordered correctly for both of those sets."]
#[doc = r""]
#[doc = r" System sets can belong to any number of other system sets,"]
#[doc =
r" allowing you to create nested hierarchies of system sets to group systems together."]
#[doc =
r" Configuration applied to system sets will flow down to their members (including other system sets),"]
#[doc =
r" allowing you to set and modify the configuration in a single place."]
#[doc = r""]
#[doc =
r" Systems sets are also useful for exposing a consistent public API for dependencies"]
#[doc = r" to hook into across versions of your crate,"]
#[doc =
r" allowing them to add systems to a specific set, or order relative to that set,"]
#[doc =
r" without leaking implementation details of the exact systems involved."]
#[doc = r""]
#[doc = r" ## Defining new system sets"]
#[doc = r""]
#[doc = r" To create a new system set, use the `#[derive(SystemSet)]` macro."]
#[doc = r" Unit structs are a good choice for one-off sets."]
#[doc = r""]
#[doc = r" ```rust"]
#[doc = r" # use bevy_ecs::prelude::*;"]
#[doc = r""]
#[doc = r" #[derive(SystemSet, Debug, Clone, PartialEq, Eq, Hash)]"]
#[doc = r" struct PhysicsSystems;"]
#[doc = r" ```"]
#[doc = r""]
#[doc = r" When you want to define several related system sets,"]
#[doc = r" consider creating an enum system set."]
#[doc = r" Each variant will be treated as a separate system set."]
#[doc = r""]
#[doc = r" ```rust"]
#[doc = r" # use bevy_ecs::prelude::*;"]
#[doc = r""]
#[doc = r" #[derive(SystemSet, Debug, Clone, PartialEq, Eq, Hash)]"]
#[doc = r" enum CombatSystems {"]
#[doc = r"    TargetSelection,"]
#[doc = r"    DamageCalculation,"]
#[doc = r"    Cleanup,"]
#[doc = r" }"]
#[doc = r" ```"]
#[doc = r""]
#[doc = r" By convention, the listed order of the system set in the enum"]
#[doc = r" corresponds to the order in which the systems are run."]
#[doc =
r" Ordering must be explicitly added to ensure that this is the case,"]
#[doc = r" but following this convention will help avoid confusion."]
#[doc = r""]
#[doc = r" ### Adding systems to system sets"]
#[doc = r""]
#[doc =
r" To add systems to a system set, call [`in_set`](crate::prelude::IntoScheduleConfigs::in_set) on the system function"]
#[doc = r" while adding it to your app or schedule."]
#[doc = r""]
#[doc =
r" Like usual, these methods can be chained with other configuration methods like [`before`](crate::prelude::IntoScheduleConfigs::before),"]
#[doc = r" or repeated to add systems to multiple sets."]
#[doc = r""]
#[doc = r" ```rust"]
#[doc = r" use bevy_ecs::prelude::*;"]
#[doc = r""]
#[doc = r" #[derive(SystemSet, Debug, Clone, PartialEq, Eq, Hash)]"]
#[doc = r" enum CombatSystems {"]
#[doc = r"    TargetSelection,"]
#[doc = r"    DamageCalculation,"]
#[doc = r"    Cleanup,"]
#[doc = r" }"]
#[doc = r""]
#[doc = r" fn target_selection() {}"]
#[doc = r""]
#[doc = r" fn enemy_damage_calculation() {}"]
#[doc = r""]
#[doc = r" fn player_damage_calculation() {}"]
#[doc = r""]
#[doc = r" let mut schedule = Schedule::default();"]
#[doc = r" // Configuring the sets to run in order."]
#[doc =
r" schedule.configure_sets((CombatSystems::TargetSelection, CombatSystems::DamageCalculation, CombatSystems::Cleanup).chain());"]
#[doc = r""]
#[doc = r" // Adding a single system to a set."]
#[doc =
r" schedule.add_systems(target_selection.in_set(CombatSystems::TargetSelection));"]
#[doc = r""]
#[doc = r" // Adding multiple systems to a set."]
#[doc =
r" schedule.add_systems((player_damage_calculation, enemy_damage_calculation).in_set(CombatSystems::DamageCalculation));"]
#[doc = r" ```"]
#[diagnostic::on_unimplemented(note =
"consider annotating `{Self}` with `#[derive(SystemSet)]`")]
pub trait SystemSet: Send + Sync + ::core::fmt::Debug + crate::label::DynEq +
    crate::label::DynHash {
    #[doc = r" Returns `Some` if this system set is a [`SystemTypeSet`]."]
    fn system_type(&self) -> Option<TypeId> { None }
    #[doc = r" Returns `true` if this system set is an [`AnonymousSet`]."]
    fn is_anonymous(&self) -> bool { false }
    /// Clones this `
    #[doc = "SystemSet"]
    ///`.
    fn dyn_clone(&self)
    -> crate::label::Box<dyn SystemSet>;
    /// Returns an [`Interned`] value corresponding to `self`.
    fn intern(&self) -> crate::intern::Interned<dyn SystemSet> where
        Self: Sized {
        SYSTEM_SET_INTERNER.intern(self)
    }
}
#[diagnostic::do_not_recommend]
impl SystemSet for crate::intern::Interned<dyn SystemSet> {
    fn system_type(&self) -> Option<TypeId> { (**self).system_type() }
    fn is_anonymous(&self) -> bool { (**self).is_anonymous() }
    fn dyn_clone(&self) -> crate::label::Box<dyn SystemSet> {
        (**self).dyn_clone()
    }
    fn intern(&self) -> Self { *self }
}
impl PartialEq for dyn SystemSet {
    fn eq(&self, other: &Self) -> bool { self.dyn_eq(other) }
}
impl Eq for dyn SystemSet {}
impl ::core::hash::Hash for dyn SystemSet {
    fn hash<H: ::core::hash::Hasher>(&self, state: &mut H) {
        self.dyn_hash(state);
    }
}
impl crate::intern::Internable for dyn SystemSet {
    fn leak(&self) -> &'static Self {
        crate::label::Box::leak(self.dyn_clone())
    }
    fn ref_eq(&self, other: &Self) -> bool {
        use ::core::ptr;
        self.type_id() == other.type_id() &&
            ptr::addr_eq(ptr::from_ref::<Self>(self),
                ptr::from_ref::<Self>(other))
    }
    fn ref_hash<H: ::core::hash::Hasher>(&self, state: &mut H) {
        use ::core::{hash::Hash, ptr};
        self.type_id().hash(state);
        ptr::from_ref::<Self>(self).cast::<()>().hash(state);
    }
}
static SYSTEM_SET_INTERNER: crate::intern::Interner<dyn SystemSet> =
    crate::intern::Interner::new();define_label!(
64    /// System sets are tag-like labels that can be used to group systems together.
65    ///
66    /// This allows you to share configuration (like run conditions) across multiple systems,
67    /// and order systems or system sets relative to conceptual groups of systems.
68    /// To control the behavior of a system set as a whole, use [`Schedule::configure_sets`](crate::prelude::Schedule::configure_sets),
69    /// or the method of the same name on `App`.
70    ///
71    /// Systems can belong to any number of system sets, reflecting multiple roles or facets that they might have.
72    /// For example, you may want to annotate a system as "consumes input" and "applies forces",
73    /// and ensure that your systems are ordered correctly for both of those sets.
74    ///
75    /// System sets can belong to any number of other system sets,
76    /// allowing you to create nested hierarchies of system sets to group systems together.
77    /// Configuration applied to system sets will flow down to their members (including other system sets),
78    /// allowing you to set and modify the configuration in a single place.
79    ///
80    /// Systems sets are also useful for exposing a consistent public API for dependencies
81    /// to hook into across versions of your crate,
82    /// allowing them to add systems to a specific set, or order relative to that set,
83    /// without leaking implementation details of the exact systems involved.
84    ///
85    /// ## Defining new system sets
86    ///
87    /// To create a new system set, use the `#[derive(SystemSet)]` macro.
88    /// Unit structs are a good choice for one-off sets.
89    ///
90    /// ```rust
91    /// # use bevy_ecs::prelude::*;
92    ///
93    /// #[derive(SystemSet, Debug, Clone, PartialEq, Eq, Hash)]
94    /// struct PhysicsSystems;
95    /// ```
96    ///
97    /// When you want to define several related system sets,
98    /// consider creating an enum system set.
99    /// Each variant will be treated as a separate system set.
100    ///
101    /// ```rust
102    /// # use bevy_ecs::prelude::*;
103    ///
104    /// #[derive(SystemSet, Debug, Clone, PartialEq, Eq, Hash)]
105    /// enum CombatSystems {
106    ///    TargetSelection,
107    ///    DamageCalculation,
108    ///    Cleanup,
109    /// }
110    /// ```
111    ///
112    /// By convention, the listed order of the system set in the enum
113    /// corresponds to the order in which the systems are run.
114    /// Ordering must be explicitly added to ensure that this is the case,
115    /// but following this convention will help avoid confusion.
116    ///
117    /// ### Adding systems to system sets
118    ///
119    /// To add systems to a system set, call [`in_set`](crate::prelude::IntoScheduleConfigs::in_set) on the system function
120    /// while adding it to your app or schedule.
121    ///
122    /// Like usual, these methods can be chained with other configuration methods like [`before`](crate::prelude::IntoScheduleConfigs::before),
123    /// or repeated to add systems to multiple sets.
124    ///
125    /// ```rust
126    /// use bevy_ecs::prelude::*;
127    ///
128    /// #[derive(SystemSet, Debug, Clone, PartialEq, Eq, Hash)]
129    /// enum CombatSystems {
130    ///    TargetSelection,
131    ///    DamageCalculation,
132    ///    Cleanup,
133    /// }
134    ///
135    /// fn target_selection() {}
136    ///
137    /// fn enemy_damage_calculation() {}
138    ///
139    /// fn player_damage_calculation() {}
140    ///
141    /// let mut schedule = Schedule::default();
142    /// // Configuring the sets to run in order.
143    /// schedule.configure_sets((CombatSystems::TargetSelection, CombatSystems::DamageCalculation, CombatSystems::Cleanup).chain());
144    ///
145    /// // Adding a single system to a set.
146    /// schedule.add_systems(target_selection.in_set(CombatSystems::TargetSelection));
147    ///
148    /// // Adding multiple systems to a set.
149    /// schedule.add_systems((player_damage_calculation, enemy_damage_calculation).in_set(CombatSystems::DamageCalculation));
150    /// ```
151    #[diagnostic::on_unimplemented(
152        note = "consider annotating `{Self}` with `#[derive(SystemSet)]`"
153    )]
154    SystemSet,
155    SYSTEM_SET_INTERNER,
156    extra_methods: {
157        /// Returns `Some` if this system set is a [`SystemTypeSet`].
158        fn system_type(&self) -> Option<TypeId> {
159            None
160        }
161
162        /// Returns `true` if this system set is an [`AnonymousSet`].
163        fn is_anonymous(&self) -> bool {
164            false
165        }
166    },
167    extra_methods_impl: {
168        fn system_type(&self) -> Option<TypeId> {
169            (**self).system_type()
170        }
171
172        fn is_anonymous(&self) -> bool {
173            (**self).is_anonymous()
174        }
175    }
176);
177
178/// A shorthand for `Interned<dyn SystemSet>`.
179pub type InternedSystemSet = Interned<dyn SystemSet>;
180/// A shorthand for `Interned<dyn ScheduleLabel>`.
181pub type InternedScheduleLabel = Interned<dyn ScheduleLabel>;
182
183/// A [`SystemSet`] grouping instances of the same function.
184///
185/// This kind of set is automatically populated and thus has some special rules:
186/// - You cannot manually add members.
187/// - You cannot configure them.
188/// - You cannot order something relative to one if it has more than one member.
189pub struct SystemTypeSet<T: 'static>(PhantomData<fn() -> T>);
190
191impl<T: 'static> SystemTypeSet<T> {
192    pub(crate) fn new() -> Self {
193        Self(PhantomData)
194    }
195}
196
197impl<T> Debug for SystemTypeSet<T> {
198    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
199        f.write_fmt(format_args!("SystemTypeSet:{0}", DebugName::type_name::<T>()))write!(f, "SystemTypeSet:{}", DebugName::type_name::<T>())
200    }
201}
202
203impl<T> Hash for SystemTypeSet<T> {
204    fn hash<H: Hasher>(&self, _state: &mut H) {
205        // all systems of a given type are the same
206    }
207}
208
209impl<T> Clone for SystemTypeSet<T> {
210    fn clone(&self) -> Self {
211        *self
212    }
213}
214
215impl<T> Copy for SystemTypeSet<T> {}
216
217impl<T> PartialEq for SystemTypeSet<T> {
218    #[inline]
219    fn eq(&self, _other: &Self) -> bool {
220        // all systems of a given type are the same
221        true
222    }
223}
224
225impl<T> Eq for SystemTypeSet<T> {}
226
227impl<T> SystemSet for SystemTypeSet<T> {
228    fn system_type(&self) -> Option<TypeId> {
229        Some(TypeId::of::<T>())
230    }
231
232    fn dyn_clone(&self) -> Box<dyn SystemSet> {
233        Box::new(*self)
234    }
235}
236
237/// A [`SystemSet`] implicitly created when using
238/// [`Schedule::add_systems`](super::Schedule::add_systems) or
239/// [`Schedule::configure_sets`](super::Schedule::configure_sets).
240#[derive(#[automatically_derived]
impl ::core::clone::Clone for AnonymousSet {
    #[inline]
    fn clone(&self) -> AnonymousSet {
        let _: ::core::clone::AssertParamIsClone<usize>;
        *self
    }
}Clone, #[automatically_derived]
impl ::core::marker::Copy for AnonymousSet { }Copy, #[automatically_derived]
impl ::core::fmt::Debug for AnonymousSet {
    #[inline]
    fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
        ::core::fmt::Formatter::debug_tuple_field1_finish(f, "AnonymousSet",
            &&self.0)
    }
}Debug, #[automatically_derived]
impl ::core::hash::Hash for AnonymousSet {
    #[inline]
    fn hash<__H: ::core::hash::Hasher>(&self, state: &mut __H) {
        ::core::hash::Hash::hash(&self.0, state)
    }
}Hash, #[automatically_derived]
impl ::core::cmp::PartialEq for AnonymousSet {
    #[inline]
    fn eq(&self, other: &AnonymousSet) -> bool { self.0 == other.0 }
}PartialEq, #[automatically_derived]
impl ::core::cmp::Eq for AnonymousSet {
    #[inline]
    #[doc(hidden)]
    #[coverage(off)]
    fn assert_fields_are_eq(&self) {
        let _: ::core::cmp::AssertParamIsEq<usize>;
    }
}Eq)]
241pub struct AnonymousSet(usize);
242
243impl AnonymousSet {
244    pub(crate) fn new(id: usize) -> Self {
245        Self(id)
246    }
247}
248
249impl SystemSet for AnonymousSet {
250    fn is_anonymous(&self) -> bool {
251        true
252    }
253
254    fn dyn_clone(&self) -> Box<dyn SystemSet> {
255        Box::new(*self)
256    }
257}
258
259/// Types that can be converted into a [`SystemSet`].
260///
261/// # Usage notes
262///
263/// This trait should only be used as a bound for trait implementations or as an
264/// argument to a function. If a system set needs to be returned from a function
265/// or stored somewhere, use [`SystemSet`] instead of this trait.
266#[diagnostic::on_unimplemented(
267    message = "`{Self}` is not a system set",
268    label = "invalid system set"
269)]
270pub trait IntoSystemSet<Marker>: Sized {
271    /// The type of [`SystemSet`] this instance converts into.
272    type Set: SystemSet;
273
274    /// Converts this instance to its associated [`SystemSet`] type.
275    fn into_system_set(self) -> Self::Set;
276}
277
278// systems sets
279impl<S: SystemSet> IntoSystemSet<()> for S {
280    type Set = Self;
281
282    #[inline]
283    fn into_system_set(self) -> Self::Set {
284        self
285    }
286}
287
288// systems
289impl<Marker, F> IntoSystemSet<(IsFunctionSystem, Marker)> for F
290where
291    Marker: 'static,
292    F: SystemParamFunction<Marker, In: FromInput<()>, Out: IntoResult<()>>,
293{
294    type Set = SystemTypeSet<F>;
295
296    #[inline]
297    fn into_system_set(self) -> Self::Set {
298        SystemTypeSet::<F>::new()
299    }
300}
301
302// exclusive systems
303impl<Marker, F> IntoSystemSet<(IsExclusiveFunctionSystem, Marker)> for F
304where
305    Marker: 'static,
306    F::Out: IntoResult<()>,
307    F: ExclusiveSystemParamFunction<Marker>,
308{
309    type Set = SystemTypeSet<F>;
310
311    #[inline]
312    fn into_system_set(self) -> Self::Set {
313        SystemTypeSet::<F>::new()
314    }
315}
316
317#[cfg(test)]
318mod tests {
319    use crate::{
320        resource::Resource,
321        schedule::{tests::ResMut, Schedule},
322        system::{IntoSystem, System},
323    };
324
325    use super::*;
326
327    #[test]
328    fn test_schedule_label() {
329        use crate::world::World;
330
331        #[derive(Resource)]
332        struct Flag(bool);
333
334        #[derive(ScheduleLabel, Debug, Default, Clone, Copy, PartialEq, Eq, Hash)]
335        struct A;
336
337        #[derive(ScheduleLabel, Debug, Default, Clone, Copy, PartialEq, Eq, Hash)]
338        struct B;
339
340        let mut world = World::new();
341
342        let mut schedule = Schedule::new(A);
343        schedule.add_systems(|mut flag: ResMut<Flag>| flag.0 = true);
344        world.add_schedule(schedule);
345
346        let interned = A.intern();
347
348        world.insert_resource(Flag(false));
349        world.run_schedule(interned);
350        assert!(world.resource::<Flag>().0);
351
352        world.insert_resource(Flag(false));
353        world.run_schedule(interned);
354        assert!(world.resource::<Flag>().0);
355
356        assert_ne!(A.intern(), B.intern());
357    }
358
359    #[test]
360    fn test_derive_schedule_label() {
361        #[derive(ScheduleLabel, Debug, Default, Clone, Copy, PartialEq, Eq, Hash)]
362        struct UnitLabel;
363
364        #[derive(ScheduleLabel, Debug, Default, Clone, Copy, PartialEq, Eq, Hash)]
365        struct TupleLabel(u32, u32);
366
367        #[derive(ScheduleLabel, Debug, Default, Clone, Copy, PartialEq, Eq, Hash)]
368        struct StructLabel {
369            a: u32,
370            b: u32,
371        }
372
373        #[expect(
374            dead_code,
375            reason = "This is a derive macro compilation test. It won't be constructed."
376        )]
377        #[derive(ScheduleLabel, Debug, Default, Clone, Copy, PartialEq, Eq, Hash)]
378        struct EmptyTupleLabel();
379
380        #[expect(
381            dead_code,
382            reason = "This is a derive macro compilation test. It won't be constructed."
383        )]
384        #[derive(ScheduleLabel, Debug, Default, Clone, Copy, PartialEq, Eq, Hash)]
385        struct EmptyStructLabel {}
386
387        #[derive(ScheduleLabel, Debug, Default, Clone, Copy, PartialEq, Eq, Hash)]
388        enum EnumLabel {
389            #[default]
390            Unit,
391            Tuple(u32, u32),
392            Struct {
393                a: u32,
394                b: u32,
395            },
396        }
397
398        #[derive(ScheduleLabel, Debug, Default, Clone, Copy, PartialEq, Eq, Hash)]
399        struct GenericLabel<T>(PhantomData<T>);
400
401        assert_eq!(UnitLabel.intern(), UnitLabel.intern());
402        assert_eq!(EnumLabel::Unit.intern(), EnumLabel::Unit.intern());
403        assert_ne!(UnitLabel.intern(), EnumLabel::Unit.intern());
404        assert_ne!(UnitLabel.intern(), TupleLabel(0, 0).intern());
405        assert_ne!(EnumLabel::Unit.intern(), EnumLabel::Tuple(0, 0).intern());
406
407        assert_eq!(TupleLabel(0, 0).intern(), TupleLabel(0, 0).intern());
408        assert_eq!(
409            EnumLabel::Tuple(0, 0).intern(),
410            EnumLabel::Tuple(0, 0).intern()
411        );
412        assert_ne!(TupleLabel(0, 0).intern(), TupleLabel(0, 1).intern());
413        assert_ne!(
414            EnumLabel::Tuple(0, 0).intern(),
415            EnumLabel::Tuple(0, 1).intern()
416        );
417        assert_ne!(TupleLabel(0, 0).intern(), EnumLabel::Tuple(0, 0).intern());
418        assert_ne!(
419            TupleLabel(0, 0).intern(),
420            StructLabel { a: 0, b: 0 }.intern()
421        );
422        assert_ne!(
423            EnumLabel::Tuple(0, 0).intern(),
424            EnumLabel::Struct { a: 0, b: 0 }.intern()
425        );
426
427        assert_eq!(
428            StructLabel { a: 0, b: 0 }.intern(),
429            StructLabel { a: 0, b: 0 }.intern()
430        );
431        assert_eq!(
432            EnumLabel::Struct { a: 0, b: 0 }.intern(),
433            EnumLabel::Struct { a: 0, b: 0 }.intern()
434        );
435        assert_ne!(
436            StructLabel { a: 0, b: 0 }.intern(),
437            StructLabel { a: 0, b: 1 }.intern()
438        );
439        assert_ne!(
440            EnumLabel::Struct { a: 0, b: 0 }.intern(),
441            EnumLabel::Struct { a: 0, b: 1 }.intern()
442        );
443        assert_ne!(
444            StructLabel { a: 0, b: 0 }.intern(),
445            EnumLabel::Struct { a: 0, b: 0 }.intern()
446        );
447        assert_ne!(
448            StructLabel { a: 0, b: 0 }.intern(),
449            EnumLabel::Struct { a: 0, b: 0 }.intern()
450        );
451        assert_ne!(StructLabel { a: 0, b: 0 }.intern(), UnitLabel.intern(),);
452        assert_ne!(
453            EnumLabel::Struct { a: 0, b: 0 }.intern(),
454            EnumLabel::Unit.intern()
455        );
456
457        assert_eq!(
458            GenericLabel::<u32>(PhantomData).intern(),
459            GenericLabel::<u32>(PhantomData).intern()
460        );
461        assert_ne!(
462            GenericLabel::<u32>(PhantomData).intern(),
463            GenericLabel::<u64>(PhantomData).intern()
464        );
465    }
466
467    #[test]
468    fn test_derive_system_set() {
469        #[derive(SystemSet, Debug, Default, Clone, Copy, PartialEq, Eq, Hash)]
470        struct UnitSet;
471
472        #[derive(SystemSet, Debug, Default, Clone, Copy, PartialEq, Eq, Hash)]
473        struct TupleSet(u32, u32);
474
475        #[derive(SystemSet, Debug, Default, Clone, Copy, PartialEq, Eq, Hash)]
476        struct StructSet {
477            a: u32,
478            b: u32,
479        }
480
481        #[expect(
482            dead_code,
483            reason = "This is a derive macro compilation test. It won't be constructed."
484        )]
485        #[derive(SystemSet, Debug, Default, Clone, Copy, PartialEq, Eq, Hash)]
486        struct EmptyTupleSet();
487
488        #[expect(
489            dead_code,
490            reason = "This is a derive macro compilation test. It won't be constructed."
491        )]
492        #[derive(SystemSet, Debug, Default, Clone, Copy, PartialEq, Eq, Hash)]
493        struct EmptyStructSet {}
494
495        #[derive(SystemSet, Debug, Default, Clone, Copy, PartialEq, Eq, Hash)]
496        enum EnumSet {
497            #[default]
498            Unit,
499            Tuple(u32, u32),
500            Struct {
501                a: u32,
502                b: u32,
503            },
504        }
505
506        #[derive(SystemSet, Debug, Default, Clone, Copy, PartialEq, Eq, Hash)]
507        struct GenericSet<T>(PhantomData<T>);
508
509        assert_eq!(UnitSet.intern(), UnitSet.intern());
510        assert_eq!(EnumSet::Unit.intern(), EnumSet::Unit.intern());
511        assert_ne!(UnitSet.intern(), EnumSet::Unit.intern());
512        assert_ne!(UnitSet.intern(), TupleSet(0, 0).intern());
513        assert_ne!(EnumSet::Unit.intern(), EnumSet::Tuple(0, 0).intern());
514
515        assert_eq!(TupleSet(0, 0).intern(), TupleSet(0, 0).intern());
516        assert_eq!(EnumSet::Tuple(0, 0).intern(), EnumSet::Tuple(0, 0).intern());
517        assert_ne!(TupleSet(0, 0).intern(), TupleSet(0, 1).intern());
518        assert_ne!(EnumSet::Tuple(0, 0).intern(), EnumSet::Tuple(0, 1).intern());
519        assert_ne!(TupleSet(0, 0).intern(), EnumSet::Tuple(0, 0).intern());
520        assert_ne!(TupleSet(0, 0).intern(), StructSet { a: 0, b: 0 }.intern());
521        assert_ne!(
522            EnumSet::Tuple(0, 0).intern(),
523            EnumSet::Struct { a: 0, b: 0 }.intern()
524        );
525
526        assert_eq!(
527            StructSet { a: 0, b: 0 }.intern(),
528            StructSet { a: 0, b: 0 }.intern()
529        );
530        assert_eq!(
531            EnumSet::Struct { a: 0, b: 0 }.intern(),
532            EnumSet::Struct { a: 0, b: 0 }.intern()
533        );
534        assert_ne!(
535            StructSet { a: 0, b: 0 }.intern(),
536            StructSet { a: 0, b: 1 }.intern()
537        );
538        assert_ne!(
539            EnumSet::Struct { a: 0, b: 0 }.intern(),
540            EnumSet::Struct { a: 0, b: 1 }.intern()
541        );
542        assert_ne!(
543            StructSet { a: 0, b: 0 }.intern(),
544            EnumSet::Struct { a: 0, b: 0 }.intern()
545        );
546        assert_ne!(
547            StructSet { a: 0, b: 0 }.intern(),
548            EnumSet::Struct { a: 0, b: 0 }.intern()
549        );
550        assert_ne!(StructSet { a: 0, b: 0 }.intern(), UnitSet.intern(),);
551        assert_ne!(
552            EnumSet::Struct { a: 0, b: 0 }.intern(),
553            EnumSet::Unit.intern()
554        );
555
556        assert_eq!(
557            GenericSet::<u32>(PhantomData).intern(),
558            GenericSet::<u32>(PhantomData).intern()
559        );
560        assert_ne!(
561            GenericSet::<u32>(PhantomData).intern(),
562            GenericSet::<u64>(PhantomData).intern()
563        );
564    }
565
566    #[test]
567    fn system_set_matches_default_system_set() {
568        fn system() {}
569        let set_from_into_system_set = IntoSystemSet::into_system_set(system).intern();
570        let system = IntoSystem::into_system(system);
571        let set_from_system = system.default_system_sets()[0];
572        assert_eq!(set_from_into_system_set, set_from_system);
573    }
574
575    #[test]
576    fn system_set_matches_default_system_set_exclusive() {
577        fn system(_: &mut crate::world::World) {}
578        let set_from_into_system_set = IntoSystemSet::into_system_set(system).intern();
579        let system = IntoSystem::into_system(system);
580        let set_from_system = system.default_system_sets()[0];
581        assert_eq!(set_from_into_system_set, set_from_system);
582    }
583}