1use 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); 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 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 pub fn run(&mut self) -> AppReturnValue {
108 let runner = self.app_runner.take();
110
111 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 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
282pub trait Plugin: 'static {
284 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}