bevy_ecs/schedule/
set.rs

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