1use alloc::boxed::Box;
2use bevy_utils::prelude::DebugName;
3use core::{
4any::TypeId,
5fmt::Debug,
6 hash::{Hash, Hasher},
7marker::PhantomData,
8};
910pub use crate::label::DynEq;
11pub use bevy_ecs_macros::{ScheduleLabel, SystemSet};
1213use crate::{
14define_label,
15intern::Interned,
16 system::{
17ExclusiveSystemParamFunction, FromInput, IntoResult, IsExclusiveFunctionSystem,
18IsFunctionSystem, SystemParamFunction,
19 },
20};
2122#[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)]
59ScheduleLabel,
60 SCHEDULE_LABEL_INTERNER
61);
6263#[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)]
154SystemSet,
155 SYSTEM_SET_INTERNER,
156 extra_methods: {
157/// Returns `Some` if this system set is a [`SystemTypeSet`].
158fn system_type(&self) -> Option<TypeId> {
159None160 }
161162/// Returns `true` if this system set is an [`AnonymousSet`].
163fn is_anonymous(&self) -> bool {
164false
165}
166 },
167 extra_methods_impl: {
168fn system_type(&self) -> Option<TypeId> {
169 (**self).system_type()
170 }
171172fn is_anonymous(&self) -> bool {
173 (**self).is_anonymous()
174 }
175 }
176);
177178/// 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>;
182183/// 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>);
190191impl<T: 'static> SystemTypeSet<T> {
192pub(crate) fn new() -> Self {
193Self(PhantomData)
194 }
195}
196197impl<T> Debugfor SystemTypeSet<T> {
198fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
199f.write_fmt(format_args!("SystemTypeSet:{0}", DebugName::type_name::<T>()))write!(f, "SystemTypeSet:{}", DebugName::type_name::<T>())200 }
201}
202203impl<T> Hashfor SystemTypeSet<T> {
204fn hash<H: Hasher>(&self, _state: &mut H) {
205// all systems of a given type are the same
206}
207}
208209impl<T> Clonefor SystemTypeSet<T> {
210fn clone(&self) -> Self {
211*self212 }
213}
214215impl<T> Copyfor SystemTypeSet<T> {}
216217impl<T> PartialEqfor SystemTypeSet<T> {
218#[inline]
219fn eq(&self, _other: &Self) -> bool {
220// all systems of a given type are the same
221true
222}
223}
224225impl<T> Eqfor SystemTypeSet<T> {}
226227impl<T> SystemSetfor SystemTypeSet<T> {
228fn system_type(&self) -> Option<TypeId> {
229Some(TypeId::of::<T>())
230 }
231232fn dyn_clone(&self) -> Box<dyn SystemSet> {
233Box::new(*self)
234 }
235}
236237/// 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);
242243impl AnonymousSet {
244pub(crate) fn new(id: usize) -> Self {
245Self(id)
246 }
247}
248249impl SystemSetfor AnonymousSet {
250fn is_anonymous(&self) -> bool {
251true
252}
253254fn dyn_clone(&self) -> Box<dyn SystemSet> {
255Box::new(*self)
256 }
257}
258259/// 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.
272type Set: SystemSet;
273274/// Converts this instance to its associated [`SystemSet`] type.
275fn into_system_set(self) -> Self::Set;
276}
277278// systems sets
279impl<S: SystemSet> IntoSystemSet<()> for S {
280type Set = Self;
281282#[inline]
283fn into_system_set(self) -> Self::Set {
284self285 }
286}
287288// systems
289impl<Marker, F> IntoSystemSet<(IsFunctionSystem, Marker)> for F
290where
291Marker: 'static,
292 F: SystemParamFunction<Marker, In: FromInput<()>, Out: IntoResult<()>>,
293{
294type Set = SystemTypeSet<F>;
295296#[inline]
297fn into_system_set(self) -> Self::Set {
298SystemTypeSet::<F>::new()
299 }
300}
301302// exclusive systems
303impl<Marker, F> IntoSystemSet<(IsExclusiveFunctionSystem, Marker)> for F
304where
305Marker: 'static,
306 F::Out: IntoResult<()>,
307 F: ExclusiveSystemParamFunction<Marker>,
308{
309type Set = SystemTypeSet<F>;
310311#[inline]
312fn into_system_set(self) -> Self::Set {
313SystemTypeSet::<F>::new()
314 }
315}
316317#[cfg(test)]
318mod tests {
319use crate::{
320 resource::Resource,
321 schedule::{tests::ResMut, Schedule},
322 system::{IntoSystem, System},
323 };
324325use super::*;
326327#[test]
328fn test_schedule_label() {
329use crate::world::World;
330331#[derive(Resource)]
332struct Flag(bool);
333334#[derive(ScheduleLabel, Debug, Default, Clone, Copy, PartialEq, Eq, Hash)]
335struct A;
336337#[derive(ScheduleLabel, Debug, Default, Clone, Copy, PartialEq, Eq, Hash)]
338struct B;
339340let mut world = World::new();
341342let mut schedule = Schedule::new(A);
343 schedule.add_systems(|mut flag: ResMut<Flag>| flag.0 = true);
344 world.add_schedule(schedule);
345346let interned = A.intern();
347348 world.insert_resource(Flag(false));
349 world.run_schedule(interned);
350assert!(world.resource::<Flag>().0);
351352 world.insert_resource(Flag(false));
353 world.run_schedule(interned);
354assert!(world.resource::<Flag>().0);
355356assert_ne!(A.intern(), B.intern());
357 }
358359#[test]
360fn test_derive_schedule_label() {
361#[derive(ScheduleLabel, Debug, Default, Clone, Copy, PartialEq, Eq, Hash)]
362struct UnitLabel;
363364#[derive(ScheduleLabel, Debug, Default, Clone, Copy, PartialEq, Eq, Hash)]
365struct TupleLabel(u32, u32);
366367#[derive(ScheduleLabel, Debug, Default, Clone, Copy, PartialEq, Eq, Hash)]
368struct StructLabel {
369 a: u32,
370 b: u32,
371 }
372373#[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)]
378struct EmptyTupleLabel();
379380#[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)]
385struct EmptyStructLabel {}
386387#[derive(ScheduleLabel, Debug, Default, Clone, Copy, PartialEq, Eq, Hash)]
388enum EnumLabel {
389#[default]
390Unit,
391 Tuple(u32, u32),
392 Struct {
393 a: u32,
394 b: u32,
395 },
396 }
397398#[derive(ScheduleLabel, Debug, Default, Clone, Copy, PartialEq, Eq, Hash)]
399struct GenericLabel<T>(PhantomData<T>);
400401assert_eq!(UnitLabel.intern(), UnitLabel.intern());
402assert_eq!(EnumLabel::Unit.intern(), EnumLabel::Unit.intern());
403assert_ne!(UnitLabel.intern(), EnumLabel::Unit.intern());
404assert_ne!(UnitLabel.intern(), TupleLabel(0, 0).intern());
405assert_ne!(EnumLabel::Unit.intern(), EnumLabel::Tuple(0, 0).intern());
406407assert_eq!(TupleLabel(0, 0).intern(), TupleLabel(0, 0).intern());
408assert_eq!(
409 EnumLabel::Tuple(0, 0).intern(),
410 EnumLabel::Tuple(0, 0).intern()
411 );
412assert_ne!(TupleLabel(0, 0).intern(), TupleLabel(0, 1).intern());
413assert_ne!(
414 EnumLabel::Tuple(0, 0).intern(),
415 EnumLabel::Tuple(0, 1).intern()
416 );
417assert_ne!(TupleLabel(0, 0).intern(), EnumLabel::Tuple(0, 0).intern());
418assert_ne!(
419 TupleLabel(0, 0).intern(),
420 StructLabel { a: 0, b: 0 }.intern()
421 );
422assert_ne!(
423 EnumLabel::Tuple(0, 0).intern(),
424 EnumLabel::Struct { a: 0, b: 0 }.intern()
425 );
426427assert_eq!(
428 StructLabel { a: 0, b: 0 }.intern(),
429 StructLabel { a: 0, b: 0 }.intern()
430 );
431assert_eq!(
432 EnumLabel::Struct { a: 0, b: 0 }.intern(),
433 EnumLabel::Struct { a: 0, b: 0 }.intern()
434 );
435assert_ne!(
436 StructLabel { a: 0, b: 0 }.intern(),
437 StructLabel { a: 0, b: 1 }.intern()
438 );
439assert_ne!(
440 EnumLabel::Struct { a: 0, b: 0 }.intern(),
441 EnumLabel::Struct { a: 0, b: 1 }.intern()
442 );
443assert_ne!(
444 StructLabel { a: 0, b: 0 }.intern(),
445 EnumLabel::Struct { a: 0, b: 0 }.intern()
446 );
447assert_ne!(
448 StructLabel { a: 0, b: 0 }.intern(),
449 EnumLabel::Struct { a: 0, b: 0 }.intern()
450 );
451assert_ne!(StructLabel { a: 0, b: 0 }.intern(), UnitLabel.intern(),);
452assert_ne!(
453 EnumLabel::Struct { a: 0, b: 0 }.intern(),
454 EnumLabel::Unit.intern()
455 );
456457assert_eq!(
458 GenericLabel::<u32>(PhantomData).intern(),
459 GenericLabel::<u32>(PhantomData).intern()
460 );
461assert_ne!(
462 GenericLabel::<u32>(PhantomData).intern(),
463 GenericLabel::<u64>(PhantomData).intern()
464 );
465 }
466467#[test]
468fn test_derive_system_set() {
469#[derive(SystemSet, Debug, Default, Clone, Copy, PartialEq, Eq, Hash)]
470struct UnitSet;
471472#[derive(SystemSet, Debug, Default, Clone, Copy, PartialEq, Eq, Hash)]
473struct TupleSet(u32, u32);
474475#[derive(SystemSet, Debug, Default, Clone, Copy, PartialEq, Eq, Hash)]
476struct StructSet {
477 a: u32,
478 b: u32,
479 }
480481#[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)]
486struct EmptyTupleSet();
487488#[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)]
493struct EmptyStructSet {}
494495#[derive(SystemSet, Debug, Default, Clone, Copy, PartialEq, Eq, Hash)]
496enum EnumSet {
497#[default]
498Unit,
499 Tuple(u32, u32),
500 Struct {
501 a: u32,
502 b: u32,
503 },
504 }
505506#[derive(SystemSet, Debug, Default, Clone, Copy, PartialEq, Eq, Hash)]
507struct GenericSet<T>(PhantomData<T>);
508509assert_eq!(UnitSet.intern(), UnitSet.intern());
510assert_eq!(EnumSet::Unit.intern(), EnumSet::Unit.intern());
511assert_ne!(UnitSet.intern(), EnumSet::Unit.intern());
512assert_ne!(UnitSet.intern(), TupleSet(0, 0).intern());
513assert_ne!(EnumSet::Unit.intern(), EnumSet::Tuple(0, 0).intern());
514515assert_eq!(TupleSet(0, 0).intern(), TupleSet(0, 0).intern());
516assert_eq!(EnumSet::Tuple(0, 0).intern(), EnumSet::Tuple(0, 0).intern());
517assert_ne!(TupleSet(0, 0).intern(), TupleSet(0, 1).intern());
518assert_ne!(EnumSet::Tuple(0, 0).intern(), EnumSet::Tuple(0, 1).intern());
519assert_ne!(TupleSet(0, 0).intern(), EnumSet::Tuple(0, 0).intern());
520assert_ne!(TupleSet(0, 0).intern(), StructSet { a: 0, b: 0 }.intern());
521assert_ne!(
522 EnumSet::Tuple(0, 0).intern(),
523 EnumSet::Struct { a: 0, b: 0 }.intern()
524 );
525526assert_eq!(
527 StructSet { a: 0, b: 0 }.intern(),
528 StructSet { a: 0, b: 0 }.intern()
529 );
530assert_eq!(
531 EnumSet::Struct { a: 0, b: 0 }.intern(),
532 EnumSet::Struct { a: 0, b: 0 }.intern()
533 );
534assert_ne!(
535 StructSet { a: 0, b: 0 }.intern(),
536 StructSet { a: 0, b: 1 }.intern()
537 );
538assert_ne!(
539 EnumSet::Struct { a: 0, b: 0 }.intern(),
540 EnumSet::Struct { a: 0, b: 1 }.intern()
541 );
542assert_ne!(
543 StructSet { a: 0, b: 0 }.intern(),
544 EnumSet::Struct { a: 0, b: 0 }.intern()
545 );
546assert_ne!(
547 StructSet { a: 0, b: 0 }.intern(),
548 EnumSet::Struct { a: 0, b: 0 }.intern()
549 );
550assert_ne!(StructSet { a: 0, b: 0 }.intern(), UnitSet.intern(),);
551assert_ne!(
552 EnumSet::Struct { a: 0, b: 0 }.intern(),
553 EnumSet::Unit.intern()
554 );
555556assert_eq!(
557 GenericSet::<u32>(PhantomData).intern(),
558 GenericSet::<u32>(PhantomData).intern()
559 );
560assert_ne!(
561 GenericSet::<u32>(PhantomData).intern(),
562 GenericSet::<u64>(PhantomData).intern()
563 );
564 }
565566#[test]
567fn system_set_matches_default_system_set() {
568fn system() {}
569let set_from_into_system_set = IntoSystemSet::into_system_set(system).intern();
570let system = IntoSystem::into_system(system);
571let set_from_system = system.default_system_sets()[0];
572assert_eq!(set_from_into_system_set, set_from_system);
573 }
574575#[test]
576fn system_set_matches_default_system_set_exclusive() {
577fn system(_: &mut crate::world::World) {}
578let set_from_into_system_set = IntoSystemSet::into_system_set(system).intern();
579let system = IntoSystem::into_system(system);
580let set_from_system = system.default_system_sets()[0];
581assert_eq!(set_from_into_system_set, set_from_system);
582 }
583}