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 ScheduleLabel,
21 SCHEDULE_LABEL_INTERNER
22);
23
24define_label!(
25 SystemSet,
27 SYSTEM_SET_INTERNER,
28 extra_methods: {
29 fn system_type(&self) -> Option<TypeId> {
31 None
32 }
33
34 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
50pub type InternedSystemSet = Interned<dyn SystemSet>;
52pub type InternedScheduleLabel = Interned<dyn ScheduleLabel>;
54
55pub 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 }
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 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#[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#[diagnostic::on_unimplemented(
153 message = "`{Self}` is not a system set",
154 label = "invalid system set"
155)]
156pub trait IntoSystemSet<Marker>: Sized {
157 type Set: SystemSet;
159
160 fn into_system_set(self) -> Self::Set;
162}
163
164impl<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
174impl<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
188impl<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}