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 ScheduleLabel,
23 SCHEDULE_LABEL_INTERNER
24);
25
26define_label!(
27 SystemSet,
29 SYSTEM_SET_INTERNER,
30 extra_methods: {
31 fn system_type(&self) -> Option<TypeId> {
33 None
34 }
35
36 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
52pub type InternedSystemSet = Interned<dyn SystemSet>;
54pub type InternedScheduleLabel = Interned<dyn ScheduleLabel>;
56
57pub 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 }
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 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#[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#[diagnostic::on_unimplemented(
155 message = "`{Self}` is not a system set",
156 label = "invalid system set"
157)]
158pub trait IntoSystemSet<Marker>: Sized {
159 type Set: SystemSet;
161
162 fn into_system_set(self) -> Self::Set;
164}
165
166impl<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
176impl<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
190impl<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}