1use std::sync::Arc;
4
5use bevy_app::{App, Plugin};
6use bevy_ecs::prelude::Resource;
7
8#[derive(Clone, Resource)]
15pub struct RenderSetup {
16 configure: Arc<dyn Fn(&mut App) + Send + Sync>,
17}
18
19impl RenderSetup {
20 pub fn new(configure: impl Fn(&mut App) + Send + Sync + 'static) -> Self {
22 Self {
23 configure: Arc::new(configure),
24 }
25 }
26}
27
28impl Plugin for RenderSetup {
29 fn build(&self, app: &mut App) {
30 (self.configure)(app);
31 }
32
33 fn is_unique(&self) -> bool {
34 false
35 }
36}
37
38#[cfg(test)]
39mod tests {
40 use std::sync::{
41 Arc,
42 atomic::{AtomicUsize, Ordering},
43 };
44
45 use bevy_app::SubApp;
46 use bevy_ecs::prelude::Resource;
47
48 use super::*;
49
50 #[derive(Resource)]
51 struct Configured(String);
52
53 #[test]
54 fn setup_is_deferred_and_reusable_across_render_apps() {
55 let calls = Arc::new(AtomicUsize::new(0));
56 let setup = RenderSetup::new({
57 let calls = Arc::clone(&calls);
58 let configuration = String::from("project configuration");
59 move |app| {
60 calls.fetch_add(1, Ordering::SeqCst);
61 app.insert_resource(Configured(configuration.clone()));
62 }
63 });
64 let cloned = setup.clone();
65 assert_eq!(calls.load(Ordering::SeqCst), 0);
66
67 for setup in [setup, cloned] {
68 let mut app = SubApp::new();
69 app.add_plugins(setup);
70 assert_eq!(
71 app.world().resource::<Configured>().0,
72 "project configuration"
73 );
74 }
75 assert_eq!(calls.load(Ordering::SeqCst), 2);
76 }
77}