swamp_app/
app.rs

1/*
2 * Copyright (c) Peter Bjorklund. All rights reserved. https://github.com/swamp/swamp
3 * Licensed under the MIT License. See LICENSE in the project root for license information.
4 */
5use std::any::type_name;
6use swamp_message::{Message, MessageId, MessageStorage, Messages, MessagesIterator};
7use swamp_resource::prelude::*;
8use swamp_system::{IntoSystem, SystemParam};
9use swamp_system_runner::{Runner, UpdatePhase};
10use swamp_system_state::State;
11use tracing::{debug, info};
12
13type AppRunner = dyn FnOnce(App) -> AppReturnValue;
14
15pub enum AppPhase {
16    WaitingForPlugins,
17    Running,
18}
19
20pub struct App {
21    app_runner: Option<Box<AppRunner>>,
22    system_runner: Runner,
23    plugins: Vec<Box<dyn Plugin>>,
24    state: State,
25    phase: AppPhase,
26}
27
28impl App {
29    pub(crate) fn internal_add_plugin(&mut self, boxed_plugin: Box<dyn Plugin>) {
30        boxed_plugin.build(self);
31        debug!(plugin=?boxed_plugin, "Added");
32        self.plugins.push(boxed_plugin);
33    }
34
35    pub fn update(&mut self) {
36        if matches!(self.phase, AppPhase::WaitingForPlugins) {
37            let mut all_are_ready = true;
38
39            for plugin in &self.plugins {
40                if !plugin.is_initialized(self) {
41                    info!("...waiting for {plugin:?}");
42                    all_are_ready = false;
43                }
44            }
45
46            if !all_are_ready {
47                return;
48            }
49            debug!("all plugins are ready, starting post initialization");
50            let mut plugins = std::mem::take(&mut self.plugins); // Temporarily take ownership of the plugins
51            for plugin in &mut plugins {
52                plugin.post_initialization(self);
53            }
54
55            info!("...post initialization complete. start running systems in schedules!");
56
57            self.plugins = plugins;
58
59            self.phase = AppPhase::Running;
60        }
61
62        // TODO: move message swapping to a tick_fn that is scheduled first in a more clean way
63        self.state.messages_mut().swap_all();
64
65        self.system_runner.run_systems(&mut self.state);
66    }
67}
68
69#[derive(Debug, Eq, PartialEq, Hash, Clone, Copy)]
70pub enum AppReturnValue {
71    Value(u32),
72}
73
74#[derive(Resource, Debug)]
75pub struct ApplicationExit {
76    pub value: AppReturnValue,
77}
78
79impl Default for App {
80    fn default() -> Self {
81        Self::new()
82    }
83}
84
85impl App {
86    pub fn new() -> Self {
87        Self {
88            app_runner: None,
89            state: State::new(),
90            plugins: Vec::default(),
91            phase: AppPhase::WaitingForPlugins,
92            system_runner: Runner::new(),
93        }
94    }
95
96    pub fn empty() -> Self {
97        Self {
98            app_runner: None,
99            state: State::new(),
100            plugins: Vec::default(),
101            phase: AppPhase::WaitingForPlugins,
102            system_runner: Runner::new(),
103        }
104    }
105
106    /// Consume self and start the runner function. It is not certain that it will ever return.
107    pub fn run(&mut self) -> AppReturnValue {
108        // Replace the runner with Dummy to take ownership
109        let runner = self.app_runner.take();
110
111        // Replace self with an empty App to take ownership and get the current self returned.
112        let app = core::mem::replace(self, Self::empty());
113
114        runner.unwrap()(app)
115    }
116
117    pub fn add_plugins<P: PluginCollection>(&mut self, collection: P) -> &mut Self {
118        collection.attach_to_app(self);
119        self
120    }
121
122    pub fn add_system<F, Params>(&mut self, update_phase: UpdatePhase, system: F)
123    where
124        F: IntoSystem<Params>,
125        Params: SystemParam,
126    {
127        self.system_runner.add_system(update_phase, system);
128    }
129
130    /// The function supplied by app_runner can in some scenarios never return.
131    pub fn set_runner(
132        &mut self,
133        app_runner: impl FnOnce(Self) -> AppReturnValue + 'static,
134    ) -> &mut Self {
135        self.app_runner = Some(Box::new(app_runner));
136        self
137    }
138
139    pub fn insert_resource<R: Resource>(&mut self, value: R) -> &mut Self {
140        debug!(resource_type=type_name::<R>(), value=?value, "inserting resource");
141        self.state.resources_mut().insert(value);
142        self
143    }
144
145    #[inline]
146    pub fn resource_take<R: Resource>(&mut self) -> R {
147        self.state.resources_mut().remove::<R>().unwrap()
148    }
149
150    #[inline]
151    pub fn get_resource_ref<R: Resource>(&self) -> Option<&R> {
152        self.state.resources().get::<R>()
153    }
154
155    #[inline]
156    pub fn get_resource_mut<R: Resource>(&mut self) -> Option<&mut R> {
157        self.state.resources_mut().get_mut::<R>()
158    }
159
160    #[inline]
161    pub fn resource<R: Resource>(&self) -> &R {
162        self.state.resources().fetch::<R>()
163    }
164
165    #[inline]
166    pub fn resource_mut<R: Resource>(&mut self) -> &mut R {
167        self.state.resources_mut().fetch_mut::<R>()
168    }
169
170    pub const fn resources(&self) -> &ResourceStorage {
171        self.state.resources()
172    }
173
174    pub fn resources_mut(&mut self) -> &mut ResourceStorage {
175        self.state.resources_mut()
176    }
177
178    #[inline]
179    pub fn has_resource<R: Resource>(&self) -> bool {
180        self.state.resources().contains::<R>()
181    }
182
183    pub fn create_message_type<M: Message>(&mut self) {
184        debug!(channel_type = type_name::<M>(), "creating message queue");
185        self.state.messages_mut().register_message_type::<M>();
186    }
187
188    pub fn get_messages<M: Message>(&mut self) -> Option<&Messages<M>> {
189        self.state.messages().get::<M>()
190    }
191
192    pub fn send<M: Message>(&mut self, message: M) -> MessageId<M> {
193        self.state
194            .messages_mut()
195            .get_mut::<M>()
196            .unwrap()
197            .send(message)
198    }
199
200    pub const fn messages(&self) -> &MessageStorage {
201        self.state.messages()
202    }
203
204    pub fn messages_mut(&mut self) -> &mut MessageStorage {
205        self.state.messages_mut()
206    }
207
208    pub fn iter_current<M: Message>(&self) -> MessagesIterator<M> {
209        self.state.messages().get::<M>().unwrap().iter_current()
210    }
211
212    pub fn iter_previous<M: Message>(&self) -> MessagesIterator<M> {
213        self.state.messages().get::<M>().unwrap().iter_previous()
214    }
215}
216
217pub trait PluginCollection {
218    fn attach_to_app(self, app: &mut App);
219}
220
221impl<T: Plugin> PluginCollection for T {
222    fn attach_to_app(self, app: &mut App) {
223        let boxed = Box::new(self);
224        app.internal_add_plugin(boxed);
225    }
226}
227
228impl<T1: Plugin, T2: Plugin> PluginCollection for (T1, T2) {
229    fn attach_to_app(self, app: &mut App) {
230        let boxed_plugin1 = Box::new(self.0);
231        let boxed_plugin2 = Box::new(self.1);
232
233        app.internal_add_plugin(boxed_plugin1);
234        app.internal_add_plugin(boxed_plugin2);
235    }
236}
237
238impl<T1: Plugin, T2: Plugin, T3: Plugin> PluginCollection for (T1, T2, T3) {
239    fn attach_to_app(self, app: &mut App) {
240        let boxed_plugin1 = Box::new(self.0);
241        let boxed_plugin2 = Box::new(self.1);
242        let boxed_plugin3 = Box::new(self.2);
243
244        app.internal_add_plugin(boxed_plugin1);
245        app.internal_add_plugin(boxed_plugin2);
246        app.internal_add_plugin(boxed_plugin3);
247    }
248}
249
250impl<T1: Plugin, T2: Plugin, T3: Plugin, T4: Plugin> PluginCollection for (T1, T2, T3, T4) {
251    fn attach_to_app(self, app: &mut App) {
252        let boxed_plugin1 = Box::new(self.0);
253        let boxed_plugin2 = Box::new(self.1);
254        let boxed_plugin3 = Box::new(self.2);
255        let boxed_plugin4 = Box::new(self.3);
256
257        app.internal_add_plugin(boxed_plugin1);
258        app.internal_add_plugin(boxed_plugin2);
259        app.internal_add_plugin(boxed_plugin3);
260        app.internal_add_plugin(boxed_plugin4);
261    }
262}
263
264impl<T1: Plugin, T2: Plugin, T3: Plugin, T4: Plugin, T5: Plugin> PluginCollection
265    for (T1, T2, T3, T4, T5)
266{
267    fn attach_to_app(self, app: &mut App) {
268        let boxed_plugin1 = Box::new(self.0);
269        let boxed_plugin2 = Box::new(self.1);
270        let boxed_plugin3 = Box::new(self.2);
271        let boxed_plugin4 = Box::new(self.3);
272        let boxed_plugin5 = Box::new(self.4);
273
274        app.internal_add_plugin(boxed_plugin1);
275        app.internal_add_plugin(boxed_plugin2);
276        app.internal_add_plugin(boxed_plugin3);
277        app.internal_add_plugin(boxed_plugin4);
278        app.internal_add_plugin(boxed_plugin5);
279    }
280}
281
282/// Plugins are not allowed to mutate themselves, just reference the app
283pub trait Plugin: 'static {
284    // Send + Sync +
285    fn build(&self, _app: &mut App) {}
286
287    fn is_initialized(&self, _app: &App) -> bool {
288        true
289    }
290
291    fn post_initialization(&self, _app: &mut App) {}
292
293    fn type_name(&self) -> &'static str {
294        type_name::<Self>()
295    }
296}
297
298impl std::fmt::Debug for dyn Plugin {
299    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
300        write!(f, "{}", self.type_name())
301    }
302}