moonshine_util/
diagnostics.rs

1//! Utilities for diagnostics and testing.
2
3use bevy_ecs::prelude::*;
4use bevy_ecs::system::RunSystemError;
5
6/// A trait similar to [`bevy_ecs::system::RunSystemOnce`], but it runs a system multiple times.
7///
8/// This is useful for testing multiple iterations of a system.
9pub trait RunSystemLoop: Sized {
10    /// Runs a system `n` times, returning a [`Vec`] of the outputs.
11    ///
12    /// # Example
13    /// ```
14    /// use bevy::prelude::*;
15    /// use moonshine_util::diagnostics::RunSystemLoop;
16    ///
17    /// let mut world = World::new();
18    /// let entities = world.run_system_loop(3, |mut commands: Commands| {
19    ///     commands.spawn_empty().id()
20    /// });
21    ///
22    /// assert_eq!(entities.len(), 3);
23    /// ```
24    fn run_system_loop<T: IntoSystem<(), Out, Marker>, Out, Marker>(
25        self,
26        n: usize,
27        system: T,
28    ) -> Vec<Result<Out, RunSystemError>> {
29        self.run_system_loop_with(n, || (), system)
30    }
31
32    /// Runs a system `n` times with the given input source, returning a [`Vec`] of the outputs.
33    ///
34    /// # Example
35    /// ```
36    /// use bevy::prelude::*;
37    /// use moonshine_util::diagnostics::RunSystemLoop;
38    ///
39    /// let mut world = World::new();
40    /// let mut names = vec!["Alice", "Bob", "Charlie"];
41    /// let entities = world.run_system_loop_with(
42    ///     3,
43    ///     || names.pop().unwrap().to_owned(),
44    ///     |In(name): In<String>, mut commands: Commands| {
45    ///         commands.spawn(Name::new(name));
46    ///     });
47    ///
48    /// assert_eq!(entities.len(), 3);
49    /// assert_eq!(world.query::<&Name>().iter(&mut world).count(), 3);
50    /// ```
51    fn run_system_loop_with<
52        InputSource,
53        T: IntoSystem<I, Out, Marker>,
54        I: SystemInput,
55        Out,
56        Marker,
57    >(
58        self,
59        n: usize,
60        input: InputSource,
61        system: T,
62    ) -> Vec<Result<Out, RunSystemError>>
63    where
64        InputSource: FnMut() -> I::Inner<'static>;
65}
66
67impl RunSystemLoop for &mut World {
68    fn run_system_loop_with<
69        InputSource,
70        T: IntoSystem<I, Out, Marker>,
71        I: SystemInput,
72        Out,
73        Marker,
74    >(
75        self,
76        n: usize,
77        mut input: InputSource,
78        system: T,
79    ) -> Vec<Result<Out, RunSystemError>>
80    where
81        InputSource: FnMut() -> I::Inner<'static>,
82    {
83        let mut system: T::System = IntoSystem::into_system(system);
84        system.initialize(self);
85        let mut outs = Vec::new();
86        for _ in 0..n {
87            let out = system.run(input(), self);
88            outs.push(out);
89            system.apply_deferred(self);
90        }
91        outs
92    }
93}