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}