bevy_ecs/schedule/
set.rs

1use alloc::boxed::Box;
2use core::{
3    any::TypeId,
4    fmt::Debug,
5    hash::{Hash, Hasher},
6    marker::PhantomData,
7};
8
9pub use crate::label::DynEq;
10pub use bevy_ecs_macros::{ScheduleLabel, SystemSet};
11
12use crate::{
13    define_label,
14    intern::Interned,
15    system::{
16        ExclusiveFunctionSystem, ExclusiveSystemParamFunction, FunctionSystem,
17        IsExclusiveFunctionSystem, IsFunctionSystem, SystemParamFunction,
18    },
19};
20
21define_label!(
22    /// A strongly-typed class of labels used to identify a [`Schedule`](crate::schedule::Schedule).
23    #[diagnostic::on_unimplemented(
24        note = "consider annotating `{Self}` with `#[derive(ScheduleLabel)]`"
25    )]
26    ScheduleLabel,
27    SCHEDULE_LABEL_INTERNER
28);
29
30define_label!(
31    /// Types that identify logical groups of systems.
32    #[diagnostic::on_unimplemented(
33        note = "consider annotating `{Self}` with `#[derive(SystemSet)]`"
34    )]
35    SystemSet,
36    SYSTEM_SET_INTERNER,
37    extra_methods: {
38        /// Returns `Some` if this system set is a [`SystemTypeSet`].
39        fn system_type(&self) -> Option<TypeId> {
40            None
41        }
42
43        /// Returns `true` if this system set is an [`AnonymousSet`].
44        fn is_anonymous(&self) -> bool {
45            false
46        }
47    },
48    extra_methods_impl: {
49        fn system_type(&self) -> Option<TypeId> {
50            (**self).system_type()
51        }
52
53        fn is_anonymous(&self) -> bool {
54            (**self).is_anonymous()
55        }
56    }
57);
58
59/// A shorthand for `Interned<dyn SystemSet>`.
60pub type InternedSystemSet = Interned<dyn SystemSet>;
61/// A shorthand for `Interned<dyn ScheduleLabel>`.
62pub type InternedScheduleLabel = Interned<dyn ScheduleLabel>;
63
64/// A [`SystemSet`] grouping instances of the same function.
65///
66/// This kind of set is automatically populated and thus has some special rules:
67/// - You cannot manually add members.
68/// - You cannot configure them.
69/// - You cannot order something relative to one if it has more than one member.
70pub struct SystemTypeSet<T: 'static>(PhantomData<fn() -> T>);
71
72impl<T: 'static> SystemTypeSet<T> {
73    pub(crate) fn new() -> Self {
74        Self(PhantomData)
75    }
76}
77
78impl<T> Debug for SystemTypeSet<T> {
79    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
80        f.debug_tuple("SystemTypeSet")
81            .field(&format_args!("fn {}()", &core::any::type_name::<T>()))
82            .finish()
83    }
84}
85
86impl<T> Hash for SystemTypeSet<T> {
87    fn hash<H: Hasher>(&self, _state: &mut H) {
88        // all systems of a given type are the same
89    }
90}
91
92impl<T> Clone for SystemTypeSet<T> {
93    fn clone(&self) -> Self {
94        *self
95    }
96}
97
98impl<T> Copy for SystemTypeSet<T> {}
99
100impl<T> PartialEq for SystemTypeSet<T> {
101    #[inline]
102    fn eq(&self, _other: &Self) -> bool {
103        // all systems of a given type are the same
104        true
105    }
106}
107
108impl<T> Eq for SystemTypeSet<T> {}
109
110impl<T> SystemSet for SystemTypeSet<T> {
111    fn system_type(&self) -> Option<TypeId> {
112        Some(TypeId::of::<T>())
113    }
114
115    fn dyn_clone(&self) -> Box<dyn SystemSet> {
116        Box::new(*self)
117    }
118
119    fn as_dyn_eq(&self) -> &dyn DynEq {
120        self
121    }
122
123    fn dyn_hash(&self, mut state: &mut dyn Hasher) {
124        TypeId::of::<Self>().hash(&mut state);
125        self.hash(&mut state);
126    }
127}
128
129/// A [`SystemSet`] implicitly created when using
130/// [`Schedule::add_systems`](super::Schedule::add_systems) or
131/// [`Schedule::configure_sets`](super::Schedule::configure_sets).
132#[derive(Clone, Copy, Debug, Hash, PartialEq, Eq)]
133pub struct AnonymousSet(usize);
134
135impl AnonymousSet {
136    pub(crate) fn new(id: usize) -> Self {
137        Self(id)
138    }
139}
140
141impl SystemSet for AnonymousSet {
142    fn is_anonymous(&self) -> bool {
143        true
144    }
145
146    fn dyn_clone(&self) -> Box<dyn SystemSet> {
147        Box::new(*self)
148    }
149
150    fn as_dyn_eq(&self) -> &dyn DynEq {
151        self
152    }
153
154    fn dyn_hash(&self, mut state: &mut dyn Hasher) {
155        TypeId::of::<Self>().hash(&mut state);
156        self.hash(&mut state);
157    }
158}
159
160/// Types that can be converted into a [`SystemSet`].
161///
162/// # Usage notes
163///
164/// This trait should only be used as a bound for trait implementations or as an
165/// argument to a function. If a system set needs to be returned from a function
166/// or stored somewhere, use [`SystemSet`] instead of this trait.
167#[diagnostic::on_unimplemented(
168    message = "`{Self}` is not a system set",
169    label = "invalid system set"
170)]
171pub trait IntoSystemSet<Marker>: Sized {
172    /// The type of [`SystemSet`] this instance converts into.
173    type Set: SystemSet;
174
175    /// Converts this instance to its associated [`SystemSet`] type.
176    fn into_system_set(self) -> Self::Set;
177}
178
179// systems sets
180impl<S: SystemSet> IntoSystemSet<()> for S {
181    type Set = Self;
182
183    #[inline]
184    fn into_system_set(self) -> Self::Set {
185        self
186    }
187}
188
189// systems
190impl<Marker, F> IntoSystemSet<(IsFunctionSystem, Marker)> for F
191where
192    Marker: 'static,
193    F: SystemParamFunction<Marker>,
194{
195    type Set = SystemTypeSet<FunctionSystem<Marker, F>>;
196
197    #[inline]
198    fn into_system_set(self) -> Self::Set {
199        SystemTypeSet::<FunctionSystem<Marker, F>>::new()
200    }
201}
202
203// exclusive systems
204impl<Marker, F> IntoSystemSet<(IsExclusiveFunctionSystem, Marker)> for F
205where
206    Marker: 'static,
207    F: ExclusiveSystemParamFunction<Marker>,
208{
209    type Set = SystemTypeSet<ExclusiveFunctionSystem<Marker, F>>;
210
211    #[inline]
212    fn into_system_set(self) -> Self::Set {
213        SystemTypeSet::<ExclusiveFunctionSystem<Marker, F>>::new()
214    }
215}
216
217#[cfg(test)]
218mod tests {
219    use crate::{
220        resource::Resource,
221        schedule::{tests::ResMut, Schedule},
222    };
223
224    use super::*;
225
226    #[test]
227    fn test_schedule_label() {
228        use crate::world::World;
229
230        #[derive(Resource)]
231        struct Flag(bool);
232
233        #[derive(ScheduleLabel, Debug, Default, Clone, Copy, PartialEq, Eq, Hash)]
234        struct A;
235
236        #[derive(ScheduleLabel, Debug, Default, Clone, Copy, PartialEq, Eq, Hash)]
237        struct B;
238
239        let mut world = World::new();
240
241        let mut schedule = Schedule::new(A);
242        schedule.add_systems(|mut flag: ResMut<Flag>| flag.0 = true);
243        world.add_schedule(schedule);
244
245        let interned = A.intern();
246
247        world.insert_resource(Flag(false));
248        world.run_schedule(interned);
249        assert!(world.resource::<Flag>().0);
250
251        world.insert_resource(Flag(false));
252        world.run_schedule(interned);
253        assert!(world.resource::<Flag>().0);
254
255        assert_ne!(A.intern(), B.intern());
256    }
257
258    #[test]
259    fn test_derive_schedule_label() {
260        #[derive(ScheduleLabel, Debug, Default, Clone, Copy, PartialEq, Eq, Hash)]
261        struct UnitLabel;
262
263        #[derive(ScheduleLabel, Debug, Default, Clone, Copy, PartialEq, Eq, Hash)]
264        struct TupleLabel(u32, u32);
265
266        #[derive(ScheduleLabel, Debug, Default, Clone, Copy, PartialEq, Eq, Hash)]
267        struct StructLabel {
268            a: u32,
269            b: u32,
270        }
271
272        #[derive(ScheduleLabel, Debug, Default, Clone, Copy, PartialEq, Eq, Hash)]
273        struct EmptyTupleLabel();
274
275        #[derive(ScheduleLabel, Debug, Default, Clone, Copy, PartialEq, Eq, Hash)]
276        struct EmptyStructLabel {}
277
278        #[derive(ScheduleLabel, Debug, Default, Clone, Copy, PartialEq, Eq, Hash)]
279        enum EnumLabel {
280            #[default]
281            Unit,
282            Tuple(u32, u32),
283            Struct {
284                a: u32,
285                b: u32,
286            },
287        }
288
289        #[derive(ScheduleLabel, Debug, Default, Clone, Copy, PartialEq, Eq, Hash)]
290        struct GenericLabel<T>(PhantomData<T>);
291
292        assert_eq!(UnitLabel.intern(), UnitLabel.intern());
293        assert_eq!(EnumLabel::Unit.intern(), EnumLabel::Unit.intern());
294        assert_ne!(UnitLabel.intern(), EnumLabel::Unit.intern());
295        assert_ne!(UnitLabel.intern(), TupleLabel(0, 0).intern());
296        assert_ne!(EnumLabel::Unit.intern(), EnumLabel::Tuple(0, 0).intern());
297
298        assert_eq!(TupleLabel(0, 0).intern(), TupleLabel(0, 0).intern());
299        assert_eq!(
300            EnumLabel::Tuple(0, 0).intern(),
301            EnumLabel::Tuple(0, 0).intern()
302        );
303        assert_ne!(TupleLabel(0, 0).intern(), TupleLabel(0, 1).intern());
304        assert_ne!(
305            EnumLabel::Tuple(0, 0).intern(),
306            EnumLabel::Tuple(0, 1).intern()
307        );
308        assert_ne!(TupleLabel(0, 0).intern(), EnumLabel::Tuple(0, 0).intern());
309        assert_ne!(
310            TupleLabel(0, 0).intern(),
311            StructLabel { a: 0, b: 0 }.intern()
312        );
313        assert_ne!(
314            EnumLabel::Tuple(0, 0).intern(),
315            EnumLabel::Struct { a: 0, b: 0 }.intern()
316        );
317
318        assert_eq!(
319            StructLabel { a: 0, b: 0 }.intern(),
320            StructLabel { a: 0, b: 0 }.intern()
321        );
322        assert_eq!(
323            EnumLabel::Struct { a: 0, b: 0 }.intern(),
324            EnumLabel::Struct { a: 0, b: 0 }.intern()
325        );
326        assert_ne!(
327            StructLabel { a: 0, b: 0 }.intern(),
328            StructLabel { a: 0, b: 1 }.intern()
329        );
330        assert_ne!(
331            EnumLabel::Struct { a: 0, b: 0 }.intern(),
332            EnumLabel::Struct { a: 0, b: 1 }.intern()
333        );
334        assert_ne!(
335            StructLabel { a: 0, b: 0 }.intern(),
336            EnumLabel::Struct { a: 0, b: 0 }.intern()
337        );
338        assert_ne!(
339            StructLabel { a: 0, b: 0 }.intern(),
340            EnumLabel::Struct { a: 0, b: 0 }.intern()
341        );
342        assert_ne!(StructLabel { a: 0, b: 0 }.intern(), UnitLabel.intern(),);
343        assert_ne!(
344            EnumLabel::Struct { a: 0, b: 0 }.intern(),
345            EnumLabel::Unit.intern()
346        );
347
348        assert_eq!(
349            GenericLabel::<u32>(PhantomData).intern(),
350            GenericLabel::<u32>(PhantomData).intern()
351        );
352        assert_ne!(
353            GenericLabel::<u32>(PhantomData).intern(),
354            GenericLabel::<u64>(PhantomData).intern()
355        );
356    }
357
358    #[test]
359    fn test_derive_system_set() {
360        #[derive(SystemSet, Debug, Default, Clone, Copy, PartialEq, Eq, Hash)]
361        struct UnitSet;
362
363        #[derive(SystemSet, Debug, Default, Clone, Copy, PartialEq, Eq, Hash)]
364        struct TupleSet(u32, u32);
365
366        #[derive(SystemSet, Debug, Default, Clone, Copy, PartialEq, Eq, Hash)]
367        struct StructSet {
368            a: u32,
369            b: u32,
370        }
371
372        #[derive(SystemSet, Debug, Default, Clone, Copy, PartialEq, Eq, Hash)]
373        struct EmptyTupleSet();
374
375        #[derive(SystemSet, Debug, Default, Clone, Copy, PartialEq, Eq, Hash)]
376        struct EmptyStructSet {}
377
378        #[derive(SystemSet, Debug, Default, Clone, Copy, PartialEq, Eq, Hash)]
379        enum EnumSet {
380            #[default]
381            Unit,
382            Tuple(u32, u32),
383            Struct {
384                a: u32,
385                b: u32,
386            },
387        }
388
389        #[derive(SystemSet, Debug, Default, Clone, Copy, PartialEq, Eq, Hash)]
390        struct GenericSet<T>(PhantomData<T>);
391
392        assert_eq!(UnitSet.intern(), UnitSet.intern());
393        assert_eq!(EnumSet::Unit.intern(), EnumSet::Unit.intern());
394        assert_ne!(UnitSet.intern(), EnumSet::Unit.intern());
395        assert_ne!(UnitSet.intern(), TupleSet(0, 0).intern());
396        assert_ne!(EnumSet::Unit.intern(), EnumSet::Tuple(0, 0).intern());
397
398        assert_eq!(TupleSet(0, 0).intern(), TupleSet(0, 0).intern());
399        assert_eq!(EnumSet::Tuple(0, 0).intern(), EnumSet::Tuple(0, 0).intern());
400        assert_ne!(TupleSet(0, 0).intern(), TupleSet(0, 1).intern());
401        assert_ne!(EnumSet::Tuple(0, 0).intern(), EnumSet::Tuple(0, 1).intern());
402        assert_ne!(TupleSet(0, 0).intern(), EnumSet::Tuple(0, 0).intern());
403        assert_ne!(TupleSet(0, 0).intern(), StructSet { a: 0, b: 0 }.intern());
404        assert_ne!(
405            EnumSet::Tuple(0, 0).intern(),
406            EnumSet::Struct { a: 0, b: 0 }.intern()
407        );
408
409        assert_eq!(
410            StructSet { a: 0, b: 0 }.intern(),
411            StructSet { a: 0, b: 0 }.intern()
412        );
413        assert_eq!(
414            EnumSet::Struct { a: 0, b: 0 }.intern(),
415            EnumSet::Struct { a: 0, b: 0 }.intern()
416        );
417        assert_ne!(
418            StructSet { a: 0, b: 0 }.intern(),
419            StructSet { a: 0, b: 1 }.intern()
420        );
421        assert_ne!(
422            EnumSet::Struct { a: 0, b: 0 }.intern(),
423            EnumSet::Struct { a: 0, b: 1 }.intern()
424        );
425        assert_ne!(
426            StructSet { a: 0, b: 0 }.intern(),
427            EnumSet::Struct { a: 0, b: 0 }.intern()
428        );
429        assert_ne!(
430            StructSet { a: 0, b: 0 }.intern(),
431            EnumSet::Struct { a: 0, b: 0 }.intern()
432        );
433        assert_ne!(StructSet { a: 0, b: 0 }.intern(), UnitSet.intern(),);
434        assert_ne!(
435            EnumSet::Struct { a: 0, b: 0 }.intern(),
436            EnumSet::Unit.intern()
437        );
438
439        assert_eq!(
440            GenericSet::<u32>(PhantomData).intern(),
441            GenericSet::<u32>(PhantomData).intern()
442        );
443        assert_ne!(
444            GenericSet::<u32>(PhantomData).intern(),
445            GenericSet::<u64>(PhantomData).intern()
446        );
447    }
448}