Skip to main content

shipyard/scheduler/
workload.rs

1mod create_workload;
2
3use crate::all_storages::AllStorages;
4use crate::component::{Component, Unique};
5use crate::scheduler::info::{DedupedLabels, TypeInfo, WorkloadInfo};
6use crate::scheduler::label::WorkloadLabel;
7use crate::scheduler::system::{ExtractWorkloadRunIf, WorkloadRunIfFn};
8use crate::scheduler::{
9    AsLabel, Batches, IntoWorkload, IntoWorkloadSystem, IntoWorkloadTrySystem, Label, Scheduler,
10    WorkloadSystem,
11};
12use crate::storage::StorageId;
13use crate::unique::UniqueStorage;
14use crate::world::World;
15use crate::{error, ShipHashMap};
16use alloc::boxed::Box;
17use core::any::TypeId;
18// macro not module
19use alloc::vec;
20use alloc::vec::Vec;
21use core::any::type_name;
22#[cfg(not(feature = "std"))]
23use core::any::Any;
24#[cfg(feature = "std")]
25use std::error::Error;
26
27/// Used to create a [`Workload`].
28///
29/// You can also use [`Workload::new`].
30///
31/// [`Workload`]: crate::Workload
32/// [`Workload::new`]: crate::Workload::new()
33#[allow(clippy::type_complexity)]
34pub struct ScheduledWorkload {
35    name: Box<dyn Label>,
36    #[allow(clippy::type_complexity)]
37    systems: Vec<Box<dyn Fn(&World) -> Result<(), error::Run> + Send + Sync + 'static>>,
38    system_names: Vec<Box<dyn Label>>,
39    #[allow(unused)]
40    system_generators: Vec<Box<dyn Fn(&mut Vec<TypeInfo>) -> TypeId + Send + Sync + 'static>>,
41    // system's `TypeId` to an index into both systems and system_names
42    #[allow(unused)]
43    lookup_table: ShipHashMap<TypeId, usize>,
44    tracking_to_enable: Vec<fn(&AllStorages) -> Result<(), error::GetStorage>>,
45    batches: Batches,
46}
47
48impl ScheduledWorkload {
49    /// Runs the workload.
50    ///
51    /// ### Borrows
52    ///
53    /// - Systems' borrow as they are executed
54    ///
55    /// ### Errors
56    ///
57    /// - Storage borrow failed.
58    /// - User error returned by system.
59    pub fn run_with_world(&self, world: &World) -> Result<(), error::RunWorkload> {
60        world.run_batches(&self.systems, &self.system_names, &self.batches, &self.name)
61    }
62
63    /// Apply tracking to all storages using it during this workload.
64    ///
65    /// ### Borrows
66    ///
67    /// - [`AllStorages`] (shared)
68    /// - Systems' storage (exclusive) to enable tracking
69    ///
70    /// ### Errors
71    ///
72    /// - [`AllStorages`] borrow failed.
73    /// - Storage borrow failed.
74    pub fn apply_tracking(&self, world: &World) -> Result<(), error::GetStorage> {
75        let all_storages = world
76            .all_storages()
77            .map_err(error::GetStorage::AllStoragesBorrow)?;
78
79        for enable_tracking_fn in &self.tracking_to_enable {
80            (enable_tracking_fn)(&all_storages)?;
81        }
82
83        Ok(())
84    }
85}
86
87impl World {
88    /// Creates a new workload and store it in the [`World`].
89    pub fn add_workload<Views, R, W, F: FnOnce() -> W + 'static>(&self, workload: F)
90    where
91        W: IntoWorkload<Views, R>,
92    {
93        let mut w = workload().into_workload();
94
95        w.tags.push(Box::new(WorkloadLabel {
96            type_id: TypeId::of::<F>(),
97            name: type_name::<F>().as_label(),
98        }));
99
100        w.name = if w.overwritten_name {
101            w.tags.push(w.name.clone());
102
103            w.name
104        } else {
105            Box::new(WorkloadLabel {
106                type_id: TypeId::of::<F>(),
107                name: type_name::<F>().as_label(),
108            })
109        };
110
111        w.add_to_world(self).unwrap();
112    }
113}
114
115/// Holds information to schedule a group of systems.
116///
117/// A workload is a collection of systems. They will execute as much in parallel as possible.\
118/// They are evaluated first to last when they can't be parallelized.\
119/// The default workload will automatically be set to the first workload added.
120pub struct Workload {
121    pub(super) name: Box<dyn Label>,
122    pub(super) tags: Vec<Box<dyn Label>>,
123    pub(super) systems: Vec<WorkloadSystem>,
124    pub(super) run_if: Option<Box<dyn WorkloadRunIfFn>>,
125    pub(super) before_all: DedupedLabels,
126    pub(super) after_all: DedupedLabels,
127    pub(super) overwritten_name: bool,
128    pub(super) require_before: DedupedLabels,
129    pub(super) require_after: DedupedLabels,
130    pub(super) barriers: Vec<usize>,
131}
132
133impl Workload {
134    /// Creates a new empty [`Workload`].
135    ///
136    /// [`Workload`]: crate::Workload
137    ///
138    /// ### Example
139    /// ```
140    /// use shipyard::{Component, IntoIter, View, ViewMut, Workload, World};
141    ///
142    /// #[derive(Component, Clone, Copy)]
143    /// struct U32(u32);
144    ///
145    /// #[derive(Component, Debug, PartialEq, Eq)]
146    /// struct USIZE(usize);
147    ///
148    /// fn add(mut usizes: ViewMut<USIZE>, u32s: View<U32>) {
149    ///     for (mut x, &y) in (&mut usizes, &u32s).iter() {
150    ///         x.0 += y.0 as usize;
151    ///     }
152    /// }
153    ///
154    /// fn check(usizes: View<USIZE>) {
155    ///     let mut iter = usizes.iter();
156    ///     assert_eq!(iter.next(), Some(&USIZE(1)));
157    ///     assert_eq!(iter.next(), Some(&USIZE(5)));
158    ///     assert_eq!(iter.next(), Some(&USIZE(9)));
159    /// }
160    ///
161    /// let mut world = World::new();
162    ///
163    /// world.add_entity((USIZE(0), U32(1)));
164    /// world.add_entity((USIZE(2), U32(3)));
165    /// world.add_entity((USIZE(4), U32(5)));
166    ///
167    /// Workload::new("Add & Check")
168    ///     .with_system(add)
169    ///     .with_system(check)
170    ///     .add_to_world(&world)
171    ///     .unwrap();
172    ///
173    /// world.run_default_workload();
174    /// ```
175    pub fn new<T>(label: impl AsLabel<T>) -> Self {
176        let label = label.as_label();
177
178        Workload {
179            systems: Vec::new(),
180            name: label.clone(),
181            run_if: None,
182            tags: vec![label],
183            before_all: DedupedLabels::new(),
184            after_all: DedupedLabels::new(),
185            overwritten_name: true,
186            require_before: DedupedLabels::new(),
187            require_after: DedupedLabels::new(),
188            barriers: Vec::new(),
189        }
190    }
191    /// Moves all systems of `other` into `Self`, leaving `other` empty.
192    /// This allows us to collect systems in different builders before joining them together.
193    pub fn append(mut self, other: &mut Self) -> Self {
194        for system in &mut other.systems {
195            system.unique_id += self.systems.len();
196        }
197
198        self.systems.append(&mut other.systems);
199
200        self
201    }
202    /// Propagates all information from `self` and `other` into their respective systems before merging their systems.
203    /// This includes `run_if`/`skip_if`, `tags`, `before`/`after` requirements.
204    pub fn merge(mut self, mut other: Workload) -> Workload {
205        self.propagate();
206        other.propagate();
207
208        let systems_len = self.systems.len();
209        self.barriers.extend(
210            other
211                .barriers
212                .drain(..)
213                .map(|barrier| barrier + systems_len),
214        );
215
216        self.append(&mut other)
217    }
218    /// Propagates all information into the systems.
219    /// This includes `run_if`/`skip_if`, `tags`, `before`/`after` requirements.
220    fn propagate(&mut self) {
221        for system in &mut self.systems {
222            system.run_if = match (system.run_if.take(), self.run_if.clone()) {
223                (None, None) => None,
224                (None, Some(run_if)) => Some(run_if.to_non_clone()),
225                (Some(run_if), None) => Some(run_if),
226                (Some(system_run_if), Some(workload_run_if)) => Some(Box::new(move |world| {
227                    Ok(workload_run_if.clone().run(world)? && (system_run_if)(world)?)
228                })),
229            };
230
231            system.tags.extend(self.tags.iter().cloned());
232
233            system.before_all.extend(self.before_all.iter().cloned());
234            system.after_all.extend(self.after_all.iter().cloned());
235            system
236                .require_before
237                .extend(self.require_before.iter().cloned());
238            system
239                .require_after
240                .extend(self.require_after.iter().cloned());
241        }
242
243        self.run_if = None;
244        self.tags.clear();
245        self.before_all.clear();
246        self.after_all.clear();
247        self.require_before.clear();
248        self.require_after.clear();
249    }
250    /// Propagates all information from `self` and `other` into their respective systems before merging their systems.
251    /// This includes `run_if`/`skip_if`, `tags`, `before`/`after` requirements.
252    pub fn with_workload(self, other: Workload) -> Workload {
253        self.merge(other)
254    }
255    /// Adds a system to the workload being created.
256    ///
257    /// ### Example:
258    /// ```
259    /// use shipyard::{Component, EntitiesViewMut, IntoIter, View, ViewMut, Workload, World};
260    ///
261    /// #[derive(Component, Clone, Copy)]
262    /// struct U32(u32);
263    ///
264    /// #[derive(Component, Debug, PartialEq, Eq)]
265    /// struct USIZE(usize);
266    ///
267    /// fn add(mut usizes: ViewMut<USIZE>, u32s: View<U32>) {
268    ///     for (mut x, &y) in (&mut usizes, &u32s).iter() {
269    ///         x.0 += y.0 as usize;
270    ///     }
271    /// }
272    ///
273    /// fn check(usizes: View<USIZE>) {
274    ///     let mut iter = usizes.iter();
275    ///     assert_eq!(iter.next(), Some(&USIZE(1)));
276    ///     assert_eq!(iter.next(), Some(&USIZE(5)));
277    ///     assert_eq!(iter.next(), Some(&USIZE(9)));
278    /// }
279    ///
280    /// let mut world = World::new();
281    ///
282    /// world.add_entity((USIZE(0), U32(1)));
283    /// world.add_entity((USIZE(2), U32(3)));
284    /// world.add_entity((USIZE(4), U32(5)));
285    ///
286    /// Workload::new("Add & Check")
287    ///     .with_system(add)
288    ///     .with_system(check)
289    ///     .add_to_world(&world)
290    ///     .unwrap();
291    ///
292    /// world.run_default_workload();
293    /// ```
294    #[track_caller]
295    pub fn with_system<B, R, S: IntoWorkloadSystem<B, R>>(mut self, system: S) -> Workload {
296        let mut system = system.into_workload_system().unwrap();
297        system.unique_id += self.systems.len();
298
299        self.systems.push(system);
300
301        self
302    }
303    /// Adds a fallible system to the workload being created.
304    /// The workload's execution will stop if any error is encountered.
305    ///
306    /// ### Example:
307    /// ```
308    /// use shipyard::{Component, EntitiesViewMut, Get, IntoIter, View, ViewMut, Workload, World};
309    /// use shipyard::error::MissingComponent;
310    ///
311    /// #[derive(Component, Clone, Copy)]
312    /// struct U32(u32);
313    ///
314    /// #[derive(Component, Debug, PartialEq, Eq)]
315    /// struct USIZE(usize);
316    ///
317    /// fn add(mut usizes: ViewMut<USIZE>, u32s: View<U32>) {
318    ///     for (mut x, &y) in (&mut usizes, &u32s).iter() {
319    ///         x.0 += y.0 as usize;
320    ///     }
321    /// }
322    ///
323    /// fn check(usizes: View<USIZE>) -> Result<(), MissingComponent> {
324    ///     for (id, i) in usizes.iter().with_id() {
325    ///         assert!(usizes.get(id)? == i);
326    ///     }
327    ///
328    ///     Ok(())
329    /// }
330    ///
331    /// let mut world = World::new();
332    ///
333    /// world.add_entity((USIZE(0), U32(1)));
334    /// world.add_entity((USIZE(2), U32(3)));
335    /// world.add_entity((USIZE(4), U32(5)));
336    ///
337    /// Workload::new("Add & Check")
338    ///     .with_system(add)
339    ///     .with_try_system(check)
340    ///     .add_to_world(&world)
341    ///     .unwrap();
342    ///
343    /// world.run_default_workload();
344    /// ```
345    #[track_caller]
346    #[cfg(feature = "std")]
347    pub fn with_try_system<
348        B,
349        Ok,
350        Err: 'static + Into<Box<dyn Error + Send + Sync>>,
351        R: Into<Result<Ok, Err>>,
352        S: IntoWorkloadTrySystem<B, R>,
353    >(
354        mut self,
355        system: S,
356    ) -> Self {
357        let mut system = system.into_workload_try_system::<Ok, Err>().unwrap();
358        system.unique_id += self.systems.len();
359
360        self.systems.push(system);
361
362        self
363    }
364    /// Adds a fallible system to the workload being created.
365    /// The workload's execution will stop if any error is encountered.
366    ///
367    /// ### Example:
368    /// ```
369    /// use shipyard::{EntitiesViewMut, Get, IntoIter, IntoWithId, View, ViewMut, Workload, World};
370    /// use shipyard::error::MissingComponent;
371    ///
372    /// fn add(mut usizes: ViewMut<usize>, u32s: View<u32>) {
373    ///     for (mut x, &y) in (&mut usizes, &u32s).iter() {
374    ///         *x += y as usize;
375    ///     }
376    /// }
377    ///
378    /// fn check(usizes: View<usize>) -> Result<(), MissingComponent> {
379    ///     for (id, i) in usizes.iter().with_id() {
380    ///         assert!(usizes.get(id)? == i);
381    ///     }
382    ///
383    ///     Ok(())
384    /// }
385    ///
386    /// let mut world = World::new();
387    ///
388    /// world.add_entity((0usize, 1u32));
389    /// world.add_entity((2usize, 3u32));
390    /// world.add_entity((4usize, 5u32));
391    ///
392    /// Workload::new("Add & Check")
393    ///     .with_system(add)
394    ///     .with_try_system(check)
395    ///     .add_to_world(&world)
396    ///     .unwrap();
397    ///
398    /// world.run_default_workload();
399    /// ```
400    #[track_caller]
401    #[cfg(not(feature = "std"))]
402    pub fn with_try_system<
403        B,
404        Ok,
405        Err: 'static + Send + Any,
406        R: Into<Result<Ok, Err>>,
407        S: IntoWorkloadTrySystem<B, R>,
408    >(
409        mut self,
410        system: S,
411    ) -> Self {
412        let mut system = system.into_workload_try_system::<Ok, Err>().unwrap();
413        system.unique_id += self.systems.len();
414
415        self.systems.push(system);
416
417        self
418    }
419    /// Finishes the workload creation and stores it in the [`World`].
420    /// Returns a struct with describing how the workload has been split in batches.
421    ///
422    /// ### Borrows
423    ///
424    /// - Scheduler (exclusive)
425    /// - [`AllStorages`] (shared)
426    /// - Systems' storage (exclusive) to enable tracking
427    ///
428    /// ### Errors
429    ///
430    /// - Scheduler borrow failed.
431    /// - Workload with an identical name already present.
432    /// - Nested workload is not present in `world`.
433    /// - [`AllStorages`] borrow failed.
434    /// - Storage borrow failed.
435    #[allow(clippy::blocks_in_conditions)]
436    pub fn add_to_world(self, world: &World) -> Result<(), error::AddWorkload> {
437        let Scheduler {
438            systems,
439            system_names,
440            system_generators,
441            lookup_table,
442            workloads,
443            workloads_info,
444            default,
445        } = &mut *world
446            .scheduler
447            .borrow_mut()
448            .map_err(|_| error::AddWorkload::Borrow)?;
449
450        let mut tracking_to_enable = Vec::new();
451
452        let name = self.name.dyn_clone();
453
454        let workload_info = create_workload::create_workload(
455            self,
456            systems,
457            system_names,
458            system_generators,
459            lookup_table,
460            &mut tracking_to_enable,
461            workloads,
462            default,
463        )?;
464
465        let all_storages = world
466            .all_storages()
467            .map_err(|_| error::AddWorkload::TrackingAllStoragesBorrow)?;
468
469        for enable_tracking_fn in &tracking_to_enable {
470            (enable_tracking_fn)(&all_storages).map_err(|err| match err {
471                error::GetStorage::StorageBorrow { name, id, borrow } => {
472                    error::AddWorkload::TrackingStorageBorrow { name, id, borrow }
473                }
474                _ => unreachable!(),
475            })?;
476        }
477
478        workloads_info.insert(name, workload_info);
479
480        Ok(())
481    }
482    /// Returns the first [`Unique`] storage borrowed by this workload that is not present in `world`.\
483    /// If the workload contains nested workloads they have to be present in the `World`.
484    ///
485    /// ### Borrows
486    ///
487    /// - AllStorages (shared)
488    pub fn are_all_uniques_present_in_world(
489        &self,
490        world: &World,
491    ) -> Result<(), error::UniquePresence> {
492        struct ComponentType;
493
494        impl Component for ComponentType {
495            type Tracking = crate::track::Untracked;
496        }
497        impl Unique for ComponentType {}
498
499        let all_storages = world
500            .all_storages
501            .borrow()
502            .map_err(|_| error::UniquePresence::AllStorages)?;
503        let storages = all_storages.storages.read();
504
505        let unique_name = type_name::<UniqueStorage<ComponentType>>()
506            .split_once('<')
507            .unwrap()
508            .0;
509
510        for work_unit in &self.systems {
511            if let Some(value) = check_uniques_in_systems(work_unit, unique_name, &storages) {
512                return value;
513            }
514        }
515
516        Ok(())
517    }
518    /// Build the [`Workload`](super::Workload) from the [`Workload`].
519    pub fn build(self) -> Result<(ScheduledWorkload, WorkloadInfo), error::AddWorkload> {
520        let mut workload = ScheduledWorkload {
521            name: self.name.clone(),
522            systems: Vec::new(),
523            system_names: Vec::new(),
524            system_generators: Vec::new(),
525            lookup_table: ShipHashMap::new(),
526            tracking_to_enable: Vec::new(),
527            batches: Batches::default(),
528        };
529
530        let workload_name = self.name.clone();
531        let mut default: Box<dyn Label> = Box::new("");
532
533        let mut workloads = ShipHashMap::new();
534
535        let workload_info = create_workload::create_workload(
536            self,
537            &mut workload.systems,
538            &mut workload.system_names,
539            &mut workload.system_generators,
540            &mut workload.lookup_table,
541            &mut workload.tracking_to_enable,
542            &mut workloads,
543            &mut default,
544        )?;
545
546        workload.batches = workloads.remove(&workload_name).unwrap();
547
548        Ok((workload, workload_info))
549    }
550
551    /// Stop parallelism between systems before and after the barrier.
552    pub fn with_barrier(mut self) -> Self {
553        self.barriers.push(self.systems.len());
554
555        self
556    }
557}
558
559fn check_uniques_in_systems(
560    system: &WorkloadSystem,
561    unique_name: &str,
562    storages: &ShipHashMap<StorageId, crate::storage::SBox>,
563) -> Option<Result<(), error::UniquePresence>> {
564    let WorkloadSystem {
565        borrow_constraints, ..
566    } = system;
567
568    for type_info in borrow_constraints {
569        if type_info.name.starts_with(unique_name) && !storages.contains_key(&type_info.storage_id)
570        {
571            return Some(Err(error::UniquePresence::Unique(type_info.clone())));
572        }
573    }
574
575    None
576}
577
578#[cfg(test)]
579mod tests {
580    use super::*;
581    use crate::component::{Component, Unique};
582    use crate::{
583        scheduler::Batches, scheduler::SystemModificator, scheduler::WorkloadModificator,
584        AllStoragesViewMut, IntoWorkload, UniqueView, UniqueViewMut, View, ViewMut, World,
585    };
586
587    struct Usize(usize);
588    #[allow(unused)]
589    struct U32(u32);
590    #[allow(unused)]
591    struct U16(u16);
592
593    impl Component for Usize {
594        type Tracking = crate::track::Untracked;
595    }
596    impl Component for U32 {
597        type Tracking = crate::track::Untracked;
598    }
599    impl Component for U16 {
600        type Tracking = crate::track::Untracked;
601    }
602    impl Unique for Usize {}
603    impl Unique for U32 {}
604    impl Unique for U16 {}
605
606    #[test]
607    fn single_immutable() {
608        fn system1(_: View<'_, Usize>) {}
609
610        let world = World::new();
611
612        Workload::new("System1")
613            .with_system(system1)
614            .add_to_world(&world)
615            .unwrap();
616
617        let scheduler = world.scheduler.borrow_mut().unwrap();
618        let label: Box<dyn Label> = Box::new("System1");
619        assert_eq!(scheduler.systems.len(), 1);
620        assert_eq!(scheduler.workloads.len(), 1);
621        assert_eq!(
622            scheduler.workloads.get(&label),
623            Some(&Batches {
624                parallel: vec![(None, vec![0])],
625                parallel_run_if: Vec::new(),
626                sequential: vec![0],
627                sequential_run_if: Vec::new(),
628                workload_run_if: None,
629                systems_run_if: Vec::new(),
630            })
631        );
632        assert_eq!(&scheduler.default, &label);
633    }
634
635    #[test]
636    fn single_mutable() {
637        fn system1(_: ViewMut<'_, Usize>) {}
638
639        let world = World::new();
640
641        Workload::new("System1")
642            .with_system(system1)
643            .add_to_world(&world)
644            .unwrap();
645
646        let scheduler = world.scheduler.borrow_mut().unwrap();
647        let label: Box<dyn Label> = Box::new("System1");
648        assert_eq!(scheduler.systems.len(), 1);
649        assert_eq!(scheduler.workloads.len(), 1);
650        assert_eq!(
651            scheduler.workloads.get(&label),
652            Some(&Batches {
653                parallel: vec![(None, vec![0])],
654                parallel_run_if: Vec::new(),
655                sequential: vec![0],
656                sequential_run_if: Vec::new(),
657                workload_run_if: None,
658                systems_run_if: Vec::new(),
659            })
660        );
661        assert_eq!(&scheduler.default, &label);
662    }
663
664    #[test]
665    fn multiple_immutable() {
666        fn system1(_: View<'_, Usize>) {}
667        fn system2(_: View<'_, Usize>) {}
668
669        let world = World::new();
670
671        Workload::new("Systems")
672            .with_system(system1)
673            .with_system(system2.into_workload_system().unwrap())
674            .add_to_world(&world)
675            .unwrap();
676
677        let scheduler = world.scheduler.borrow_mut().unwrap();
678        let label: Box<dyn Label> = Box::new("Systems");
679        assert_eq!(scheduler.systems.len(), 2);
680        assert_eq!(scheduler.workloads.len(), 1);
681        assert_eq!(
682            scheduler.workloads.get(&label),
683            Some(&Batches {
684                parallel: vec![(None, vec![0, 1])],
685                parallel_run_if: Vec::new(),
686                sequential: vec![0, 1],
687                sequential_run_if: Vec::new(),
688                workload_run_if: None,
689                systems_run_if: Vec::new(),
690            })
691        );
692        assert_eq!(&scheduler.default, &label);
693    }
694
695    #[test]
696    fn multiple_mutable() {
697        fn system1(_: ViewMut<'_, Usize>) {}
698        fn system2(_: ViewMut<'_, Usize>) {}
699
700        let world = World::new();
701
702        Workload::new("Systems")
703            .with_system(system1)
704            .with_system(system2)
705            .add_to_world(&world)
706            .unwrap();
707
708        let scheduler = world.scheduler.borrow_mut().unwrap();
709        let label: Box<dyn Label> = Box::new("Systems");
710        assert_eq!(scheduler.systems.len(), 2);
711        assert_eq!(scheduler.workloads.len(), 1);
712        assert_eq!(
713            scheduler.workloads.get(&label),
714            Some(&Batches {
715                parallel: vec![(None, vec![0]), (None, vec![1])],
716                parallel_run_if: Vec::new(),
717                sequential: vec![0, 1],
718                sequential_run_if: Vec::new(),
719                workload_run_if: None,
720                systems_run_if: Vec::new(),
721            })
722        );
723        assert_eq!(&scheduler.default, &label);
724    }
725
726    #[test]
727    fn multiple_mixed() {
728        fn system1(_: ViewMut<'_, Usize>) {}
729        fn system2(_: View<'_, Usize>) {}
730
731        let world = World::new();
732
733        Workload::new("Systems")
734            .with_system(system1)
735            .with_system(system2)
736            .add_to_world(&world)
737            .unwrap();
738
739        let scheduler = world.scheduler.borrow_mut().unwrap();
740        let label: Box<dyn Label> = Box::new("Systems");
741        assert_eq!(scheduler.systems.len(), 2);
742        assert_eq!(scheduler.workloads.len(), 1);
743        assert_eq!(
744            scheduler.workloads.get(&label),
745            Some(&Batches {
746                parallel: vec![(None, vec![0]), (None, vec![1])],
747                parallel_run_if: Vec::new(),
748                sequential: vec![0, 1],
749                sequential_run_if: Vec::new(),
750                workload_run_if: None,
751                systems_run_if: Vec::new(),
752            })
753        );
754        assert_eq!(&scheduler.default, &label);
755
756        let world = World::new();
757
758        Workload::new("Systems")
759            .with_system(system2)
760            .with_system(system1)
761            .add_to_world(&world)
762            .unwrap();
763
764        let scheduler = world.scheduler.borrow_mut().unwrap();
765        let label: Box<dyn Label> = Box::new("Systems");
766        assert_eq!(scheduler.systems.len(), 2);
767        assert_eq!(scheduler.workloads.len(), 1);
768        assert_eq!(
769            scheduler.workloads.get(&label),
770            Some(&Batches {
771                parallel: vec![(None, vec![0]), (None, vec![1])],
772                parallel_run_if: Vec::new(),
773                sequential: vec![0, 1],
774                sequential_run_if: Vec::new(),
775                workload_run_if: None,
776                systems_run_if: Vec::new(),
777            })
778        );
779        assert_eq!(&scheduler.default, &label);
780    }
781
782    #[test]
783    fn append_optimizes_batches() {
784        fn system_a1(_: View<'_, Usize>, _: ViewMut<'_, U32>) {}
785        fn system_a2(_: View<'_, Usize>, _: ViewMut<'_, U32>) {}
786        fn system_b1(_: View<'_, Usize>) {}
787
788        let world = World::new();
789
790        let mut group_a = Workload::new("Group A")
791            .with_system(system_a1)
792            .with_system(system_a2);
793
794        let mut group_b = Workload::new("Group B").with_system(system_b1);
795
796        Workload::new("Combined")
797            .append(&mut group_a)
798            .append(&mut group_b)
799            .add_to_world(&world)
800            .unwrap();
801
802        let scheduler = world.scheduler.borrow_mut().unwrap();
803        let label: Box<dyn Label> = Box::new("Combined");
804        assert_eq!(scheduler.systems.len(), 3);
805        assert_eq!(scheduler.workloads.len(), 1);
806        assert_eq!(
807            scheduler.workloads.get(&label),
808            Some(&Batches {
809                parallel: vec![(None, vec![0]), (None, vec![1, 2])],
810                parallel_run_if: Vec::new(),
811                sequential: vec![0, 1, 2],
812                sequential_run_if: Vec::new(),
813                workload_run_if: None,
814                systems_run_if: Vec::new(),
815            })
816        );
817        assert_eq!(&scheduler.default, &label);
818    }
819
820    #[test]
821    fn all_storages() {
822        fn system1(_: View<'_, Usize>) {}
823        fn system2(_: AllStoragesViewMut<'_>) {}
824
825        let world = World::new();
826
827        Workload::new("Systems")
828            .with_system(system2)
829            .add_to_world(&world)
830            .unwrap();
831
832        let scheduler = world.scheduler.borrow_mut().unwrap();
833        let label: Box<dyn Label> = Box::new("Systems");
834        assert_eq!(scheduler.systems.len(), 1);
835        assert_eq!(scheduler.workloads.len(), 1);
836        assert_eq!(
837            scheduler.workloads.get(&label),
838            Some(&Batches {
839                parallel: vec![(Some(0), Vec::new())],
840                parallel_run_if: Vec::new(),
841                sequential: vec![0],
842                sequential_run_if: Vec::new(),
843                workload_run_if: None,
844                systems_run_if: Vec::new(),
845            })
846        );
847        assert_eq!(&scheduler.default, &label);
848
849        let world = World::new();
850
851        Workload::new("Systems")
852            .with_system(system2)
853            .with_system(system2)
854            .add_to_world(&world)
855            .unwrap();
856
857        let scheduler = world.scheduler.borrow_mut().unwrap();
858        assert_eq!(scheduler.systems.len(), 1);
859        assert_eq!(scheduler.workloads.len(), 1);
860        assert_eq!(
861            scheduler.workloads.get(&label),
862            Some(&Batches {
863                parallel: vec![(Some(0), Vec::new()), (Some(0), Vec::new())],
864                parallel_run_if: Vec::new(),
865                sequential: vec![0, 0],
866                sequential_run_if: Vec::new(),
867                workload_run_if: None,
868                systems_run_if: Vec::new(),
869            })
870        );
871        assert_eq!(&scheduler.default, &label);
872
873        let world = World::new();
874
875        Workload::new("Systems")
876            .with_system(system1)
877            .with_system(system2)
878            .add_to_world(&world)
879            .unwrap();
880
881        let scheduler = world.scheduler.borrow_mut().unwrap();
882        let label: Box<dyn Label> = Box::new("Systems");
883        assert_eq!(scheduler.systems.len(), 2);
884        assert_eq!(scheduler.workloads.len(), 1);
885        assert_eq!(
886            scheduler.workloads.get(&label),
887            Some(&Batches {
888                parallel: vec![(None, vec![0]), (Some(1), Vec::new())],
889                parallel_run_if: Vec::new(),
890                sequential: vec![0, 1],
891                sequential_run_if: Vec::new(),
892                workload_run_if: None,
893                systems_run_if: Vec::new(),
894            })
895        );
896        assert_eq!(&scheduler.default, &label);
897
898        let world = World::new();
899
900        Workload::new("Systems")
901            .with_system(system2)
902            .with_system(system1)
903            .add_to_world(&world)
904            .unwrap();
905
906        let scheduler = world.scheduler.borrow_mut().unwrap();
907        assert_eq!(scheduler.systems.len(), 2);
908        assert_eq!(scheduler.workloads.len(), 1);
909        assert_eq!(
910            scheduler.workloads.get(&label),
911            Some(&Batches {
912                parallel: vec![(Some(0), Vec::new()), (None, vec![1])],
913                parallel_run_if: Vec::new(),
914                sequential: vec![0, 1],
915                sequential_run_if: Vec::new(),
916                workload_run_if: None,
917                systems_run_if: Vec::new(),
918            })
919        );
920        assert_eq!(&scheduler.default, &label);
921    }
922
923    #[cfg(feature = "thread_local")]
924    #[test]
925    fn non_send() {
926        use crate::borrow::NonSend;
927
928        #[allow(unused)]
929        struct NotSend(*const ());
930        unsafe impl Sync for NotSend {}
931        impl Component for NotSend {
932            type Tracking = crate::track::Untracked;
933        }
934
935        fn sys1(_: NonSend<View<'_, NotSend>>) {}
936        fn sys2(_: NonSend<ViewMut<'_, NotSend>>) {}
937        fn sys3(_: View<'_, Usize>) {}
938        fn sys4(_: ViewMut<'_, Usize>) {}
939
940        let world = World::new();
941
942        Workload::new("Test")
943            .with_system(sys1)
944            .with_system(sys1)
945            .add_to_world(&world)
946            .unwrap();
947
948        let scheduler = world.scheduler.borrow_mut().unwrap();
949        let label: Box<dyn Label> = Box::new("Test");
950        assert_eq!(scheduler.systems.len(), 1);
951        assert_eq!(scheduler.workloads.len(), 1);
952        assert_eq!(
953            scheduler.workloads.get(&label),
954            Some(&Batches {
955                parallel: vec![(None, vec![0, 0])],
956                parallel_run_if: Vec::new(),
957                sequential: vec![0, 0],
958                sequential_run_if: Vec::new(),
959                workload_run_if: None,
960                systems_run_if: Vec::new(),
961            })
962        );
963        assert_eq!(&scheduler.default, &label);
964        assert!(
965            scheduler.workloads_info[&label].batches_info[0].systems.1[0]
966                .conflict
967                .is_none()
968        );
969
970        let world = World::new();
971
972        Workload::new("Test")
973            .with_system(sys1)
974            .with_system(sys2)
975            .add_to_world(&world)
976            .unwrap();
977
978        let scheduler = world.scheduler.borrow_mut().unwrap();
979        assert_eq!(scheduler.systems.len(), 2);
980        assert_eq!(scheduler.workloads.len(), 1);
981        assert_eq!(
982            scheduler.workloads.get(&label),
983            Some(&Batches {
984                parallel: vec![(None, vec![0]), (Some(1), Vec::new())],
985                parallel_run_if: Vec::new(),
986                sequential: vec![0, 1],
987                sequential_run_if: Vec::new(),
988                workload_run_if: None,
989                systems_run_if: Vec::new(),
990            })
991        );
992        assert_eq!(&scheduler.default, &label);
993
994        let world = World::new();
995
996        Workload::new("Test")
997            .with_system(sys2)
998            .with_system(sys1)
999            .add_to_world(&world)
1000            .unwrap();
1001
1002        let scheduler = world.scheduler.borrow_mut().unwrap();
1003        assert_eq!(scheduler.systems.len(), 2);
1004        assert_eq!(scheduler.workloads.len(), 1);
1005        assert_eq!(
1006            scheduler.workloads.get(&label),
1007            Some(&Batches {
1008                parallel: vec![(Some(0), Vec::new()), (None, vec![1])],
1009                parallel_run_if: Vec::new(),
1010                sequential: vec![0, 1],
1011                sequential_run_if: Vec::new(),
1012                workload_run_if: None,
1013                systems_run_if: Vec::new(),
1014            })
1015        );
1016        assert_eq!(&scheduler.default, &label);
1017
1018        let world = World::new();
1019
1020        Workload::new("Test")
1021            .with_system(sys1)
1022            .with_system(sys3)
1023            .add_to_world(&world)
1024            .unwrap();
1025
1026        let scheduler = world.scheduler.borrow_mut().unwrap();
1027        assert_eq!(scheduler.systems.len(), 2);
1028        assert_eq!(scheduler.workloads.len(), 1);
1029        assert_eq!(
1030            scheduler.workloads.get(&label),
1031            Some(&Batches {
1032                parallel: vec![(None, vec![0, 1])],
1033                parallel_run_if: Vec::new(),
1034                sequential: vec![0, 1],
1035                sequential_run_if: Vec::new(),
1036                workload_run_if: None,
1037                systems_run_if: Vec::new(),
1038            })
1039        );
1040        assert_eq!(&scheduler.default, &label);
1041        assert!(
1042            scheduler.workloads_info[&label].batches_info[0].systems.1[0]
1043                .conflict
1044                .is_none()
1045        );
1046
1047        let world = World::new();
1048
1049        Workload::new("Test")
1050            .with_system(sys1)
1051            .with_system(sys4)
1052            .add_to_world(&world)
1053            .unwrap();
1054
1055        let scheduler = world.scheduler.borrow_mut().unwrap();
1056        assert_eq!(scheduler.systems.len(), 2);
1057        assert_eq!(scheduler.workloads.len(), 1);
1058        assert_eq!(
1059            scheduler.workloads.get(&label),
1060            Some(&Batches {
1061                parallel: vec![(None, vec![0, 1])],
1062                parallel_run_if: Vec::new(),
1063                sequential: vec![0, 1],
1064                sequential_run_if: Vec::new(),
1065                workload_run_if: None,
1066                systems_run_if: Vec::new(),
1067            })
1068        );
1069        assert_eq!(&scheduler.default, &label);
1070    }
1071
1072    #[test]
1073    fn unique_and_non_unique() {
1074        fn system1(_: ViewMut<'_, Usize>) {}
1075        fn system2(_: UniqueViewMut<'_, Usize>) {}
1076
1077        let world = World::new();
1078
1079        Workload::new("Systems")
1080            .with_system(system1)
1081            .with_system(system2)
1082            .add_to_world(&world)
1083            .unwrap();
1084
1085        let scheduler = world.scheduler.borrow_mut().unwrap();
1086        let label: Box<dyn Label> = Box::new("Systems");
1087        assert_eq!(scheduler.systems.len(), 2);
1088        assert_eq!(scheduler.workloads.len(), 1);
1089        assert_eq!(
1090            scheduler.workloads.get(&label),
1091            Some(&Batches {
1092                parallel: vec![(None, vec![0, 1])],
1093                parallel_run_if: Vec::new(),
1094                sequential: vec![0, 1],
1095                sequential_run_if: Vec::new(),
1096                workload_run_if: None,
1097                systems_run_if: Vec::new(),
1098            })
1099        );
1100        assert_eq!(&scheduler.default, &label);
1101    }
1102
1103    #[test]
1104    fn empty_workload() {
1105        let world = World::new();
1106
1107        Workload::new("Systems").add_to_world(&world).unwrap();
1108
1109        let scheduler = world.scheduler.borrow_mut().unwrap();
1110        let label: Box<dyn Label> = Box::new("Systems");
1111        assert_eq!(scheduler.systems.len(), 0);
1112        assert_eq!(scheduler.workloads.len(), 1);
1113        assert_eq!(
1114            scheduler.workloads.get(&label),
1115            Some(&Batches {
1116                parallel: vec![],
1117                parallel_run_if: Vec::new(),
1118                sequential: vec![],
1119                sequential_run_if: Vec::new(),
1120                workload_run_if: None,
1121                systems_run_if: Vec::new(),
1122            })
1123        );
1124        assert_eq!(&scheduler.default, &label);
1125    }
1126
1127    #[test]
1128    fn append_ensures_multiple_batches_can_be_optimized_over() {
1129        fn sys_a1(_: ViewMut<'_, Usize>, _: ViewMut<'_, U32>) {}
1130        fn sys_a2(_: View<'_, Usize>, _: ViewMut<'_, U32>) {}
1131        fn sys_b1(_: View<'_, Usize>) {}
1132        fn sys_c1(_: View<'_, U16>) {}
1133
1134        let world = World::new();
1135
1136        let mut group_a = Workload::new("Group A")
1137            .with_system(sys_a1)
1138            .with_system(sys_a2);
1139        let mut group_b = Workload::new("Group B").with_system(sys_b1);
1140        let mut group_c = Workload::new("Group C").with_system(sys_c1);
1141
1142        Workload::new("Combined")
1143            .append(&mut group_a)
1144            .append(&mut group_b)
1145            .append(&mut group_c)
1146            .add_to_world(&world)
1147            .unwrap();
1148
1149        let scheduler = world.scheduler.borrow_mut().unwrap();
1150        let label: Box<dyn Label> = Box::new("Combined");
1151        assert_eq!(scheduler.systems.len(), 4);
1152        assert_eq!(scheduler.workloads.len(), 1);
1153        assert_eq!(
1154            scheduler.workloads.get(&label),
1155            Some(&Batches {
1156                parallel: vec![(None, vec![0]), (None, vec![1, 2, 3])],
1157                parallel_run_if: Vec::new(),
1158                sequential: vec![0, 1, 2, 3],
1159                sequential_run_if: Vec::new(),
1160                workload_run_if: None,
1161                systems_run_if: Vec::new(),
1162            })
1163        );
1164        assert_eq!(&scheduler.default, &label);
1165    }
1166
1167    #[test]
1168    fn skip_if_missing_storage() {
1169        let world = World::new();
1170
1171        Workload::new("test")
1172            .skip_if_storage_empty::<Usize>()
1173            .with_system(|| panic!())
1174            .build()
1175            .unwrap()
1176            .0
1177            .run_with_world(&world)
1178            .unwrap();
1179
1180        Workload::new("test")
1181            .skip_if_storage_empty::<Usize>()
1182            .with_system(|| panic!())
1183            .add_to_world(&world)
1184            .unwrap();
1185
1186        world.run_default_workload().unwrap();
1187    }
1188
1189    #[test]
1190    fn system_skip_if_missing_storage() {
1191        let world = World::new();
1192
1193        Workload::new("test")
1194            .with_system((|| -> () { panic!() }).skip_if_storage_empty::<Usize>())
1195            .build()
1196            .unwrap()
1197            .0
1198            .run_with_world(&world)
1199            .unwrap();
1200
1201        Workload::new("test")
1202            .with_system((|| -> () { panic!() }).skip_if_storage_empty::<Usize>())
1203            .add_to_world(&world)
1204            .unwrap();
1205
1206        world.run_default_workload().unwrap();
1207    }
1208
1209    #[test]
1210    fn skip_if_empty_storage() {
1211        let mut world = World::new();
1212
1213        let eid = world.add_entity((Usize(0),));
1214        world.remove::<(Usize,)>(eid);
1215
1216        Workload::new("test")
1217            .skip_if_storage_empty::<Usize>()
1218            .with_system(|| -> () { panic!() })
1219            .build()
1220            .unwrap()
1221            .0
1222            .run_with_world(&world)
1223            .unwrap();
1224
1225        Workload::new("test")
1226            .skip_if_storage_empty::<Usize>()
1227            .with_system(|| -> () { panic!() })
1228            .add_to_world(&world)
1229            .unwrap();
1230
1231        world.run_default_workload().unwrap();
1232    }
1233
1234    #[test]
1235    fn system_skip_if_empty_storage() {
1236        let mut world = World::new();
1237
1238        let eid = world.add_entity((Usize(0),));
1239        world.remove::<(Usize,)>(eid);
1240
1241        Workload::new("test")
1242            .with_system((|| -> () { panic!() }).skip_if_storage_empty::<Usize>())
1243            .build()
1244            .unwrap()
1245            .0
1246            .run_with_world(&world)
1247            .unwrap();
1248
1249        Workload::new("test")
1250            .with_system((|| -> () { panic!() }).skip_if_storage_empty::<Usize>())
1251            .add_to_world(&world)
1252            .unwrap();
1253
1254        world.run_default_workload().unwrap();
1255    }
1256
1257    #[test]
1258    fn workload_merge_skip_if() {
1259        let world = World::new();
1260
1261        world.add_unique(Usize(0));
1262
1263        world.add_workload(|| {
1264            (
1265                (|| -> () { panic!() })
1266                    .into_workload()
1267                    .skip_if_missing_unique::<U32>(),
1268                (|mut u: UniqueViewMut<'_, Usize>| u.0 += 1).into_workload(),
1269            )
1270        });
1271
1272        world.run_default_workload().unwrap();
1273
1274        assert_eq!(world.borrow::<UniqueView<'_, Usize>>().unwrap().0, 1);
1275    }
1276
1277    #[test]
1278    fn before_after() {
1279        fn a() {}
1280        fn b() {}
1281        fn c() {}
1282        fn d() {}
1283
1284        let (workload, _) = Workload::new("")
1285            .with_system(d.after_all(b))
1286            .with_system(c.after_all(b))
1287            .with_system(b.after_all(a))
1288            .with_system(a)
1289            .build()
1290            .unwrap();
1291
1292        let batches = &workload.batches;
1293        assert_eq!(batches.sequential, &[3, 2, 0, 1]);
1294        assert_eq!(
1295            batches.parallel,
1296            &[(None, vec![3]), (None, vec![2]), (None, vec![0, 1])]
1297        );
1298
1299        let (workload, _) = Workload::new("")
1300            .with_system(a)
1301            .with_system(b.after_all(a))
1302            .with_system(c.after_all(b))
1303            .build()
1304            .unwrap();
1305
1306        let batches = &workload.batches;
1307        assert_eq!(batches.sequential, &[0, 1, 2]);
1308        assert_eq!(
1309            batches.parallel,
1310            &[(None, vec![0]), (None, vec![1]), (None, vec![2])]
1311        );
1312
1313        let (workload, _) = Workload::new("")
1314            .with_system(b.after_all(a))
1315            .with_system(a)
1316            .with_system(c.after_all(b))
1317            .build()
1318            .unwrap();
1319
1320        let batches = &workload.batches;
1321        assert_eq!(batches.sequential, &[1, 0, 2]);
1322        assert_eq!(
1323            batches.parallel,
1324            &[(None, vec![1]), (None, vec![0]), (None, vec![2])]
1325        );
1326    }
1327
1328    #[test]
1329    fn before_after_no_anchor() {
1330        fn a() {}
1331        fn b() {}
1332
1333        let (workload, _) = Workload::new("")
1334            .with_system(a.before_all(b))
1335            .with_system(b.after_all(a))
1336            .build()
1337            .unwrap();
1338
1339        let batches = &workload.batches;
1340        assert_eq!(batches.sequential, &[0, 1]);
1341        assert_eq!(batches.parallel, &[(None, vec![0]), (None, vec![1])]);
1342
1343        let (workload, _) = Workload::new("")
1344            .with_system(b.after_all(a))
1345            .with_system(a.before_all(b))
1346            .build()
1347            .unwrap();
1348
1349        let batches = &workload.batches;
1350        assert_eq!(batches.sequential, &[1, 0]);
1351        assert_eq!(batches.parallel, &[(None, vec![1]), (None, vec![0])]);
1352    }
1353
1354    #[test]
1355    fn before_after_missing_system() {
1356        fn a() {}
1357        fn b() {}
1358
1359        let (workload, _) = Workload::new("")
1360            .with_system(a.before_all(b))
1361            .build()
1362            .unwrap();
1363
1364        let batches = &workload.batches;
1365        assert_eq!(batches.sequential, &[0]);
1366        assert_eq!(batches.parallel, &[(None, vec![0])]);
1367    }
1368
1369    #[test]
1370    fn before_after_absent_system() {
1371        fn a() {}
1372        fn b() {}
1373        fn c() {}
1374
1375        let (workload, _) = Workload::new("")
1376            .with_system(a)
1377            .with_system(c.after_all(b))
1378            .build()
1379            .unwrap();
1380
1381        // HashMap makes this error random between a and c
1382        let batches = &workload.batches;
1383        assert!(batches.sequential == [0, 1] || batches.sequential == [1, 0]);
1384        assert_eq!(batches.parallel, &[(None, vec![0, 1])]);
1385    }
1386
1387    #[test]
1388    fn before_after_system_label() {
1389        fn a() {}
1390        fn b() {}
1391        fn c() {}
1392
1393        let (workload, _) = Workload::new("")
1394            .with_system(a.tag("a"))
1395            .with_system(
1396                b.tag("b")
1397                    .before_all("a")
1398                    .require_after("a")
1399                    .require_before("c"),
1400            )
1401            .with_system(c.tag("c").before_all("b").require_after("b"))
1402            .build()
1403            .unwrap();
1404
1405        let batches = &workload.batches;
1406        assert_eq!(batches.sequential, &[2, 1, 0]);
1407        assert_eq!(
1408            batches.parallel,
1409            &[(None, vec![2]), (None, vec![1]), (None, vec![0])]
1410        );
1411
1412        let (workload, _) = Workload::new("")
1413            .with_system(c.tag("c").after_all("b"))
1414            .with_system(b.tag("b").after_all("a"))
1415            .with_system(a.tag("a"))
1416            .build()
1417            .unwrap();
1418
1419        let batches = &workload.batches;
1420        assert_eq!(batches.sequential, &[2, 1, 0]);
1421        assert_eq!(
1422            batches.parallel,
1423            &[(None, vec![2]), (None, vec![1]), (None, vec![0])]
1424        );
1425    }
1426
1427    #[test]
1428    fn after_all_single_system() {
1429        let (workload, _) = Workload::new("")
1430            .with_system((|| {}).tag("this"))
1431            .with_system((|_: AllStoragesViewMut<'_>| {}).after_all("this"))
1432            .with_system((|_: View<'_, Usize>| {}).after_all("this"))
1433            .build()
1434            .unwrap();
1435
1436        let batches = &workload.batches;
1437
1438        assert_eq!(
1439            batches,
1440            &Batches {
1441                parallel: vec![(None, vec![0]), (Some(1), vec![]), (None, vec![2])],
1442                parallel_run_if: Vec::new(),
1443                sequential: vec![0, 1, 2],
1444                sequential_run_if: Vec::new(),
1445                workload_run_if: None,
1446                systems_run_if: Vec::new()
1447            }
1448        );
1449    }
1450
1451    #[test]
1452    fn sequential_workload() {
1453        fn sys0() {}
1454        fn sys1() {}
1455        fn sys2() {}
1456        fn workload1() -> Workload {
1457            (sys0, sys1, sys2).into_sequential_workload()
1458        }
1459
1460        let (workload, _) = workload1().rename("").build().unwrap();
1461
1462        let batches = &workload.batches;
1463        assert_eq!(batches.sequential, &[0, 1, 2]);
1464        assert_eq!(
1465            batches.parallel,
1466            &[(None, vec![0]), (None, vec![1]), (None, vec![2])]
1467        );
1468    }
1469
1470    #[test]
1471    fn before_after_borrow_conflict() {
1472        fn sys0(_: View<'_, U32>) {}
1473        fn sys1(_: AllStoragesViewMut<'_>) {}
1474
1475        let (workload, _) = (sys0, sys1.before_all("not present"), sys0)
1476            .into_workload()
1477            .rename("")
1478            .build()
1479            .unwrap();
1480
1481        let batches = &workload.batches;
1482        assert_eq!(
1483            batches.parallel,
1484            &[(None, vec![0]), (Some(1), Vec::new()), (None, vec![0])]
1485        );
1486        assert_eq!(batches.sequential, &[0, 1, 0]);
1487    }
1488
1489    #[test]
1490    fn contains() {
1491        fn type_name_of<T: 'static>(_: &T) -> &'static str {
1492            type_name::<T>()
1493        }
1494        fn type_id_of<T: 'static>(_: &T) -> TypeId {
1495            TypeId::of::<T>()
1496        }
1497
1498        fn w() -> Workload {
1499            (|| {}).into_workload()
1500        }
1501        let world = World::builder()
1502            .with_custom_lock::<parking_lot::RawRwLock>()
1503            .build();
1504        world.add_workload(w);
1505        assert!(world.contains_workload(WorkloadLabel {
1506            type_id: type_id_of(&w),
1507            name: type_name_of(&w).as_label()
1508        }));
1509        assert!(world.contains_workload(w));
1510        world.run_workload(w).unwrap();
1511    }
1512
1513    #[test]
1514    fn barrier() {
1515        let workload = Workload::new("")
1516            .with_system(|| {})
1517            .with_system(|| {})
1518            .with_barrier()
1519            .with_system(|| {})
1520            .with_system(|| {})
1521            .with_barrier()
1522            .with_system(|| {})
1523            .with_system(|| {})
1524            .build()
1525            .unwrap();
1526
1527        assert_eq!(workload.1.batches_info.len(), 3);
1528
1529        let workload = Workload::new("")
1530            .with_barrier()
1531            .with_system(|| {})
1532            .with_system(|| {})
1533            .build()
1534            .unwrap();
1535
1536        assert_eq!(workload.1.batches_info.len(), 1);
1537
1538        let workload = Workload::new("")
1539            .with_system(|| {})
1540            .with_system(|| {})
1541            .with_barrier()
1542            .build()
1543            .unwrap();
1544
1545        assert_eq!(workload.1.batches_info.len(), 1);
1546    }
1547
1548    #[test]
1549    fn with_system_return_type() {
1550        Workload::new("").with_system(|| 0usize).build().unwrap();
1551    }
1552
1553    #[test]
1554    fn try_system_run_if() {
1555        fn try_sys() -> Result<(), error::MissingComponent> {
1556            Err(error::MissingComponent {
1557                id: crate::EntityId::dead(),
1558                name: "",
1559            })
1560        }
1561
1562        let (workload, _) = Workload::new("")
1563            .with_try_system(try_sys.into_workload_try_system().unwrap().run_if(|| true))
1564            .build()
1565            .unwrap();
1566
1567        let world = World::new();
1568
1569        assert!(workload
1570            .run_with_world(&world)
1571            .err()
1572            .unwrap()
1573            .custom_error()
1574            .is_some());
1575    }
1576
1577    /// Checks that cycles created using `after_all` are properly detected.
1578    #[test]
1579    fn cycle_detection_after_all() {
1580        fn sys_a() {}
1581        fn sys_b() {}
1582        fn workload_cycle() -> Workload {
1583            (sys_a.after_all(sys_b), sys_b.after_all(sys_a)).into_workload()
1584        }
1585
1586        let result = workload_cycle().build();
1587
1588        assert!(matches!(
1589            result,
1590            Err(error::AddWorkload::ImpossibleRequirements(
1591                error::ImpossibleRequirements::Cycle(_)
1592            ))
1593        ));
1594    }
1595
1596    /// Checks that cycles created using `before_all` and `after_all` are properly detected.
1597    ///
1598    /// This also affects implicit ordering.\
1599    /// Here `sys_b` is implicitely after `sys_a` and `sys_c` tries to be both before and after them.
1600    #[test]
1601    fn cycle_detection_before_after_all() {
1602        fn sys_a() {}
1603        fn sys_b() {}
1604        fn sys_c() {}
1605        fn workload_cycle() -> Workload {
1606            (sys_a, sys_b, sys_c.before_all(sys_a).after_all(sys_b)).into_workload()
1607        }
1608
1609        let result = workload_cycle().build();
1610
1611        assert!(matches!(
1612            result,
1613            Err(error::AddWorkload::ImpossibleRequirements(_))
1614        ));
1615    }
1616
1617    /// Checks that `before_all` cannot override `with_barrier`.
1618    #[test]
1619    fn cycle_barrier() {
1620        fn sys_a() {}
1621        fn sys_b() {}
1622
1623        let result = Workload::new("")
1624            .with_system(sys_a)
1625            .with_barrier()
1626            .with_system(sys_b.before_all(sys_a))
1627            .build();
1628
1629        assert!(matches!(
1630            result,
1631            Err(error::AddWorkload::ImpossibleRequirements(
1632                error::ImpossibleRequirements::Cycle(_)
1633            ))
1634        ));
1635    }
1636
1637    /// Checks that `before_all`, `after_all`, `with_barrier` and implicit ordering all play well together.
1638    #[test]
1639    fn complex_ordering() {
1640        fn sys_a() {}
1641        fn sys_b() {}
1642        fn sys_c() {}
1643        fn sys_d() {}
1644
1645        let (workload, _) = Workload::new("")
1646            .with_system(sys_a)
1647            .with_system(sys_b)
1648            .with_system(sys_c.after_all(sys_a).before_all(sys_b))
1649            .with_barrier()
1650            .with_system(sys_d)
1651            .build()
1652            .unwrap();
1653
1654        let batches = &workload.batches;
1655        assert_eq!(
1656            batches.parallel,
1657            &[
1658                (None, vec![0]),
1659                (None, vec![2]),
1660                (None, vec![1]),
1661                (None, vec![3])
1662            ]
1663        );
1664        assert_eq!(batches.sequential, &[0, 2, 1, 3]);
1665    }
1666
1667    #[test]
1668    fn require_in_workload() {
1669        fn sys_a() {}
1670        fn sys_b() {}
1671        fn sys_c() {}
1672
1673        Workload::new("")
1674            .with_system(sys_a.require_in_workload(sys_b))
1675            .with_system(sys_b)
1676            .build()
1677            .unwrap();
1678        Workload::new("")
1679            .with_system(sys_a)
1680            .with_system(sys_b.require_in_workload(sys_a))
1681            .build()
1682            .unwrap();
1683
1684        let result = Workload::new("")
1685            .with_system(sys_c)
1686            .with_system(sys_a.require_in_workload(sys_b))
1687            .with_system(sys_c)
1688            .build();
1689
1690        assert_eq!(
1691            result.err(),
1692            Some(error::AddWorkload::MissingInWorkload(
1693                sys_a.as_label(),
1694                vec![sys_b.as_label()]
1695            ))
1696        );
1697    }
1698
1699    #[test]
1700    fn require_before() {
1701        fn sys_a() {}
1702        fn sys_b() {}
1703
1704        Workload::new("")
1705            .with_system(sys_a.after_all(sys_b).require_before(sys_b))
1706            .with_system(sys_b)
1707            .build()
1708            .unwrap();
1709        Workload::new("")
1710            .with_system(sys_a)
1711            .with_system(sys_b.after_all(sys_a).require_before(sys_a))
1712            .build()
1713            .unwrap();
1714        Workload::new("")
1715            .with_system(sys_a)
1716            .with_barrier()
1717            .with_system(sys_b.require_before(sys_a))
1718            .build()
1719            .unwrap();
1720        Workload::new("")
1721            .with_system((|_: AllStoragesViewMut<'_>| {}).tag("sys_a"))
1722            .with_system((|_: AllStoragesViewMut<'_>| {}).require_before("sys_a"))
1723            .build()
1724            .unwrap();
1725
1726        // These systems don't conflict and would run in parallel
1727        let result = Workload::new("")
1728            .with_system(sys_a)
1729            .with_system(sys_b.require_before(sys_a))
1730            .build();
1731
1732        assert_eq!(
1733            result.err(),
1734            Some(error::AddWorkload::MissingBefore(
1735                sys_b.as_label(),
1736                vec![sys_a.as_label()]
1737            ))
1738        );
1739    }
1740
1741    #[test]
1742    fn require_after() {
1743        fn sys_a() {}
1744        fn sys_b() {}
1745
1746        Workload::new("")
1747            .with_system(sys_a)
1748            .with_system(sys_b.before_all(sys_a).require_after(sys_a))
1749            .build()
1750            .unwrap();
1751        Workload::new("")
1752            .with_system(sys_a.before_all(sys_b).require_after(sys_b))
1753            .with_system(sys_b)
1754            .build()
1755            .unwrap();
1756        Workload::new("")
1757            .with_system(sys_a.require_after(sys_b))
1758            .with_barrier()
1759            .with_system(sys_b)
1760            .build()
1761            .unwrap();
1762        Workload::new("")
1763            .with_system((|_: AllStoragesViewMut<'_>| {}).require_after("sys_a"))
1764            .with_system((|_: AllStoragesViewMut<'_>| {}).tag("sys_a"))
1765            .build()
1766            .unwrap();
1767
1768        // These systems don't conflict and would run in parallel
1769        let result = Workload::new("")
1770            .with_system(sys_a.require_after(sys_b))
1771            .with_system(sys_b)
1772            .build();
1773
1774        assert_eq!(
1775            result.err(),
1776            Some(error::AddWorkload::MissingAfter(
1777                sys_a.as_label(),
1778                vec![sys_b.as_label()]
1779            ))
1780        );
1781    }
1782}
1783
1784/// Tests related to `WorkloadInfo` and not system ordering.
1785#[cfg(test)]
1786mod info_tests {
1787    use super::*;
1788    use crate::borrow::Mutability;
1789    use crate::scheduler::info::{BeforeAfterConstraint, Conflict, SystemInfo};
1790    use crate::scheduler::system_modificator::SystemModificator;
1791    use crate::sparse_set::SparseSet;
1792    use crate::views::{View, ViewMut};
1793    use alloc::format;
1794    use std::string::ToString;
1795
1796    #[allow(unused)]
1797    struct Usize(usize);
1798    impl Component for Usize {
1799        type Tracking = crate::track::Untracked;
1800    }
1801    #[allow(unused)]
1802    struct U32(u32);
1803    impl Component for U32 {
1804        type Tracking = crate::track::Untracked;
1805    }
1806
1807    #[test]
1808    fn before_all() {
1809        fn sys_a() {}
1810        fn sys_b() {}
1811
1812        let (_, info) = Workload::new("workload 1")
1813            .with_system(sys_a)
1814            .with_system(sys_b.before_all(sys_a))
1815            .build()
1816            .unwrap();
1817
1818        assert_eq!(info.name, "workload 1");
1819        assert_eq!(info.batches_info.len(), 2);
1820
1821        let mut systems0 = info.batches_info[0].systems();
1822        assert_eq!(
1823            systems0.next(),
1824            Some(&SystemInfo {
1825                name: "System(shipyard::scheduler::workload::info_tests::before_all::sys_b)"
1826                    .to_string(),
1827                borrow: vec![],
1828                conflict: None,
1829                after: vec![],
1830                after_all: vec![],
1831                before_all: vec![BeforeAfterConstraint {
1832                    other_system: 0,
1833                    constraint:
1834                        "System(shipyard::scheduler::workload::info_tests::before_all::sys_a)"
1835                            .to_string()
1836                }],
1837                unique_id: 1
1838            })
1839        );
1840        assert_eq!(systems0.next(), None);
1841
1842        let mut systems1 = info.batches_info[1].systems();
1843        assert_eq!(
1844            systems1.next(),
1845            Some(&SystemInfo {
1846                name: "System(shipyard::scheduler::workload::info_tests::before_all::sys_a)"
1847                    .to_string(),
1848                borrow: vec![],
1849                conflict: None,
1850                after: vec![1],
1851                after_all: vec![],
1852                before_all: vec![],
1853                unique_id: 0
1854            })
1855        );
1856        assert_eq!(systems1.next(), None);
1857    }
1858
1859    #[test]
1860    fn after_all() {
1861        fn sys_a() {}
1862        fn sys_b() {}
1863
1864        let (_, info) = Workload::new("workload 1")
1865            .with_system(sys_a.after_all(sys_b))
1866            .with_system(sys_b)
1867            .build()
1868            .unwrap();
1869
1870        assert_eq!(info.name, "workload 1");
1871        assert_eq!(info.batches_info.len(), 2);
1872
1873        let mut systems0 = info.batches_info[0].systems();
1874        assert_eq!(
1875            systems0.next(),
1876            Some(&SystemInfo {
1877                name: "System(shipyard::scheduler::workload::info_tests::after_all::sys_b)"
1878                    .to_string(),
1879                borrow: vec![],
1880                conflict: None,
1881                after: vec![],
1882                after_all: vec![],
1883                before_all: vec![],
1884                unique_id: 1
1885            })
1886        );
1887        assert_eq!(systems0.next(), None);
1888
1889        let mut systems1 = info.batches_info[1].systems();
1890        assert_eq!(
1891            systems1.next(),
1892            Some(&SystemInfo {
1893                name: "System(shipyard::scheduler::workload::info_tests::after_all::sys_a)"
1894                    .to_string(),
1895                borrow: vec![],
1896                conflict: None,
1897                after: vec![1],
1898                after_all: vec![BeforeAfterConstraint {
1899                    other_system: 1,
1900                    constraint:
1901                        "System(shipyard::scheduler::workload::info_tests::after_all::sys_b)"
1902                            .to_string()
1903                }],
1904                before_all: vec![],
1905                unique_id: 0
1906            })
1907        );
1908        assert_eq!(systems1.next(), None);
1909    }
1910
1911    #[test]
1912    fn borrow() {
1913        fn sys_a(_: View<'_, Usize>, _: View<'_, U32>) {}
1914        fn sys_b(_: ViewMut<'_, Usize>, _: View<'_, U32>) {}
1915        fn sys_c(_: View<'_, Usize>) {}
1916        fn sys_d(_: View<'_, Usize>) {}
1917
1918        let (_, info) = Workload::new("")
1919            .with_system(sys_a)
1920            .with_system(sys_b)
1921            .with_system(sys_c)
1922            .with_system(sys_d)
1923            .build()
1924            .unwrap();
1925
1926        let mut systems0 = info.batches_info[0].systems();
1927        assert_eq!(
1928            systems0.next(),
1929            Some(&SystemInfo {
1930                name: format!("{:?}", sys_a.as_label()),
1931                borrow: vec![
1932                    TypeInfo {
1933                        name: type_name::<SparseSet::<Usize>>().into(),
1934                        mutability: Mutability::Shared,
1935                        storage_id: StorageId::of::<SparseSet<Usize>>(),
1936                        thread_safe: true
1937                    },
1938                    TypeInfo {
1939                        name: type_name::<SparseSet::<U32>>().into(),
1940                        mutability: Mutability::Shared,
1941                        storage_id: StorageId::of::<SparseSet<U32>>(),
1942                        thread_safe: true
1943                    }
1944                ],
1945                conflict: None,
1946                after: vec![],
1947                after_all: vec![],
1948                before_all: vec![],
1949                unique_id: 0
1950            })
1951        );
1952
1953        let mut systems1 = info.batches_info[1].systems();
1954        assert_eq!(
1955            systems1.next(),
1956            Some(&SystemInfo {
1957                name: format!("{:?}", sys_b.as_label()),
1958                borrow: vec![
1959                    TypeInfo {
1960                        name: type_name::<SparseSet::<Usize>>().into(),
1961                        mutability: Mutability::Exclusive,
1962                        storage_id: StorageId::of::<SparseSet<Usize>>(),
1963                        thread_safe: true
1964                    },
1965                    TypeInfo {
1966                        name: type_name::<SparseSet::<U32>>().into(),
1967                        mutability: Mutability::Shared,
1968                        storage_id: StorageId::of::<SparseSet<U32>>(),
1969                        thread_safe: true
1970                    }
1971                ],
1972                conflict: Some(Conflict::Borrow {
1973                    type_info: TypeInfo {
1974                        name: type_name::<SparseSet::<Usize>>().into(),
1975                        mutability: Mutability::Exclusive,
1976                        storage_id: StorageId::of::<SparseSet<Usize>>(),
1977                        thread_safe: true
1978                    },
1979                    other_system: 0,
1980                    other_type_info: TypeInfo {
1981                        name: type_name::<SparseSet::<Usize>>().into(),
1982                        mutability: Mutability::Shared,
1983                        storage_id: StorageId::of::<SparseSet<Usize>>(),
1984                        thread_safe: true
1985                    }
1986                }),
1987                after: vec![0],
1988                after_all: vec![],
1989                before_all: vec![],
1990                unique_id: 1
1991            })
1992        );
1993
1994        let mut systems2 = info.batches_info[2].systems();
1995        assert_eq!(
1996            systems2.next(),
1997            Some(&SystemInfo {
1998                name: format!("{:?}", sys_c.as_label()),
1999                borrow: vec![TypeInfo {
2000                    name: type_name::<SparseSet::<Usize>>().into(),
2001                    mutability: Mutability::Shared,
2002                    storage_id: StorageId::of::<SparseSet<Usize>>(),
2003                    thread_safe: true
2004                },],
2005                conflict: Some(Conflict::Borrow {
2006                    type_info: TypeInfo {
2007                        name: type_name::<SparseSet::<Usize>>().into(),
2008                        mutability: Mutability::Shared,
2009                        storage_id: StorageId::of::<SparseSet<Usize>>(),
2010                        thread_safe: true
2011                    },
2012                    other_system: 1,
2013                    other_type_info: TypeInfo {
2014                        name: type_name::<SparseSet::<Usize>>().into(),
2015                        mutability: Mutability::Exclusive,
2016                        storage_id: StorageId::of::<SparseSet<Usize>>(),
2017                        thread_safe: true
2018                    }
2019                }),
2020                after: vec![1],
2021                after_all: vec![],
2022                before_all: vec![],
2023                unique_id: 2
2024            })
2025        );
2026        assert_eq!(
2027            systems2.next(),
2028            Some(&SystemInfo {
2029                name: format!("{:?}", sys_d.as_label()),
2030                borrow: vec![TypeInfo {
2031                    name: type_name::<SparseSet::<Usize>>().into(),
2032                    mutability: Mutability::Shared,
2033                    storage_id: StorageId::of::<SparseSet<Usize>>(),
2034                    thread_safe: true
2035                },],
2036                conflict: Some(Conflict::Borrow {
2037                    type_info: TypeInfo {
2038                        name: type_name::<SparseSet::<Usize>>().into(),
2039                        mutability: Mutability::Shared,
2040                        storage_id: StorageId::of::<SparseSet<Usize>>(),
2041                        thread_safe: true
2042                    },
2043                    other_system: 1,
2044                    other_type_info: TypeInfo {
2045                        name: type_name::<SparseSet::<Usize>>().into(),
2046                        mutability: Mutability::Exclusive,
2047                        storage_id: StorageId::of::<SparseSet<Usize>>(),
2048                        thread_safe: true
2049                    }
2050                }),
2051                after: vec![1],
2052                after_all: vec![],
2053                before_all: vec![],
2054                unique_id: 3
2055            })
2056        );
2057    }
2058}