bevy_ecs/schedule/
set.rs

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