1use limnus_local_resource::{LocalResource, LocalResourceStorage};
6use limnus_message::{Message, MessageId, MessageStorage, Messages, MessagesIterator};
7use limnus_resource::prelude::*;
8use limnus_scheduler::Scheduler;
9use limnus_scheduler_runner::Runner;
10use limnus_stage::{Stage, StageTag, Stages};
11use limnus_system::{IntoSystem, SystemParam};
12use limnus_system_state::State;
13use std::any::type_name;
14use tracing::{debug, info};
15
16type AppRunner = dyn FnOnce(App) -> AppReturnValue;
17
18pub enum AppPhase {
19 WaitingForPlugins,
20 Running,
21}
22
23pub struct App {
24 app_runner: Option<Box<AppRunner>>,
25 schedulers_runner: Runner,
26 plugins: Vec<Box<dyn Plugin>>,
27 state: State,
28 phase: AppPhase,
29 stages: Stages,
30}
31
32impl App {
33 pub(crate) fn internal_add_plugin(&mut self, boxed_plugin: Box<dyn Plugin>) {
34 boxed_plugin.build(self);
35 debug!(plugin=?boxed_plugin, "Added");
36 self.plugins.push(boxed_plugin);
37 }
38
39 pub fn update(&mut self) {
40 if matches!(self.phase, AppPhase::WaitingForPlugins) {
41 let mut all_are_ready = true;
42
43 for plugin in &self.plugins {
44 if !plugin.is_initialized(self) {
45 info!("...waiting for {plugin:?}");
46 all_are_ready = false;
47 }
48 }
49
50 if !all_are_ready {
51 return;
52 }
53 debug!("all plugins are ready, starting post initialization");
54 let mut plugins = std::mem::take(&mut self.plugins); for plugin in &mut plugins {
56 plugin.post_initialization(self);
57 }
58
59 info!("...post initialization complete. start running systems in schedules!");
60
61 self.plugins = plugins;
62
63 self.phase = AppPhase::Running;
64 }
65
66 self.schedulers_runner
67 .run_schedulers(&self.stages, &mut self.state);
68 }
69}
70
71#[derive(Debug, Eq, PartialEq, Hash, Clone, Copy)]
72pub enum AppReturnValue {
73 Value(u32),
74}
75
76#[derive(Resource, Debug)]
77pub struct ApplicationExit {
78 pub value: AppReturnValue,
79}
80
81impl Default for App {
82 fn default() -> Self {
83 Self::new()
84 }
85}
86
87impl App {
88 #[must_use]
89 pub fn new() -> Self {
90 Self {
91 app_runner: None,
92 state: State::new(),
93 plugins: Vec::default(),
94 phase: AppPhase::WaitingForPlugins,
95 schedulers_runner: Runner::new(),
96 stages: Stages::new(),
97 }
98 }
99
100 #[must_use]
101 pub fn empty() -> Self {
102 Self {
103 app_runner: None,
104 state: State::new(),
105 plugins: Vec::default(),
106 phase: AppPhase::WaitingForPlugins,
107 schedulers_runner: Runner::new(),
108 stages: Stages::new(),
109 }
110 }
111
112 pub fn run(&mut self) -> AppReturnValue {
114 let runner = self.app_runner.take();
116
117 let app = core::mem::replace(self, Self::empty());
119
120 runner.unwrap()(app)
121 }
122
123 pub fn add_plugins<P: PluginCollection>(&mut self, collection: P) -> &mut Self {
124 collection.attach_to_app(self);
125 self
126 }
127
128 pub fn add_stage<S>(&mut self)
129 where
130 S: StageTag,
131 {
132 let stage = Stage::new();
133 self.stages.add::<S>(stage);
134 }
135
136 pub fn add_system<F, Params, S>(&mut self, _stage_tag: S, system: F)
139 where
140 F: IntoSystem<Params>,
141 Params: SystemParam,
142 S: StageTag,
143 {
144 self.stages
145 .get_mut::<S>()
146 .expect("could not find stage")
147 .add_system(system);
148 }
149
150 pub fn add_scheduler<T>(&mut self, scheduler: T)
151 where
152 T: Scheduler,
153 {
154 self.schedulers_runner.add_scheduler(scheduler);
155 }
156
157 pub fn set_runner(
159 &mut self,
160 app_runner: impl FnOnce(Self) -> AppReturnValue + 'static,
161 ) -> &mut Self {
162 self.app_runner = Some(Box::new(app_runner));
163 self
164 }
165
166 pub fn insert_resource<R: Resource>(&mut self, value: R) -> &mut Self {
167 debug!(resource_type=type_name::<R>(), value=?value, "inserting resource");
168 self.state.resources_mut().insert(value);
169 self
170 }
171
172 pub fn insert_local_resource<R: LocalResource>(&mut self, value: R) -> &mut Self {
173 debug!(resource_type=type_name::<R>(), value=?value, "inserting local resource");
174 self.state.local_resources_mut().insert(value);
175 self
176 }
177
178 #[inline]
179 pub fn resource_take<R: Resource>(&mut self) -> R {
180 self.state.resources_mut().remove::<R>().unwrap()
181 }
182
183 #[inline]
184 #[must_use]
185 pub fn get_resource_ref<R: Resource>(&self) -> Option<&R> {
186 self.state.resources().get::<R>()
187 }
188
189 #[inline]
190 pub fn get_resource_mut<R: Resource>(&mut self) -> Option<&mut R> {
191 self.state.resources_mut().get_mut::<R>()
192 }
193
194 #[inline]
195 #[must_use]
196 pub fn resource<R: Resource>(&self) -> &R {
197 self.state.resources().fetch::<R>()
198 }
199
200 #[inline]
201 pub fn resource_mut<R: Resource>(&mut self) -> &mut R {
202 self.state.resources_mut().fetch_mut::<R>()
203 }
204
205 #[must_use]
206 pub const fn resources(&self) -> &ResourceStorage {
207 self.state.resources()
208 }
209
210 pub fn resources_mut(&mut self) -> &mut ResourceStorage {
211 self.state.resources_mut()
212 }
213
214 #[must_use]
215 pub const fn local_resources(&self) -> &LocalResourceStorage {
216 self.state.local_resources()
217 }
218
219 #[inline]
220 #[must_use]
221 pub fn has_resource<R: Resource>(&self) -> bool {
222 self.state.resources().contains::<R>()
223 }
224
225 pub fn create_message_type<M: Message>(&mut self) {
226 debug!(channel_type = type_name::<M>(), "creating message queue");
227 self.state.messages_mut().register_message_type::<M>();
228 }
229
230 #[must_use]
231 pub fn get_messages<M: Message>(&self) -> Option<&Messages<M>> {
232 self.state.messages().get::<M>()
233 }
234
235 pub fn send<M: Message>(&mut self, message: M) -> MessageId<M> {
236 self.state
237 .messages_mut()
238 .get_mut::<M>()
239 .unwrap()
240 .send(message)
241 }
242
243 #[must_use]
244 pub const fn messages(&self) -> &MessageStorage {
245 self.state.messages()
246 }
247
248 pub fn messages_mut(&mut self) -> &mut MessageStorage {
249 self.state.messages_mut()
250 }
251
252 #[must_use]
253 pub fn iter_current<M: Message>(&self) -> MessagesIterator<M> {
254 self.state.messages().get::<M>().unwrap().iter_current()
255 }
256
257 #[must_use]
258 pub fn iter_previous<M: Message>(&self) -> MessagesIterator<M> {
259 self.state.messages().get::<M>().unwrap().iter_previous()
260 }
261}
262
263pub trait PluginCollection {
264 fn attach_to_app(self, app: &mut App);
265}
266
267impl<T: Plugin> PluginCollection for T {
268 fn attach_to_app(self, app: &mut App) {
269 let boxed = Box::new(self);
270 app.internal_add_plugin(boxed);
271 }
272}
273
274impl<T1: Plugin, T2: Plugin> PluginCollection for (T1, T2) {
275 fn attach_to_app(self, app: &mut App) {
276 let boxed_plugin1 = Box::new(self.0);
277 let boxed_plugin2 = Box::new(self.1);
278
279 app.internal_add_plugin(boxed_plugin1);
280 app.internal_add_plugin(boxed_plugin2);
281 }
282}
283
284impl<T1: Plugin, T2: Plugin, T3: Plugin> PluginCollection for (T1, T2, T3) {
285 fn attach_to_app(self, app: &mut App) {
286 let boxed_plugin1 = Box::new(self.0);
287 let boxed_plugin2 = Box::new(self.1);
288 let boxed_plugin3 = Box::new(self.2);
289
290 app.internal_add_plugin(boxed_plugin1);
291 app.internal_add_plugin(boxed_plugin2);
292 app.internal_add_plugin(boxed_plugin3);
293 }
294}
295
296impl<T1: Plugin, T2: Plugin, T3: Plugin, T4: Plugin> PluginCollection for (T1, T2, T3, T4) {
297 fn attach_to_app(self, app: &mut App) {
298 let boxed_plugin1 = Box::new(self.0);
299 let boxed_plugin2 = Box::new(self.1);
300 let boxed_plugin3 = Box::new(self.2);
301 let boxed_plugin4 = Box::new(self.3);
302
303 app.internal_add_plugin(boxed_plugin1);
304 app.internal_add_plugin(boxed_plugin2);
305 app.internal_add_plugin(boxed_plugin3);
306 app.internal_add_plugin(boxed_plugin4);
307 }
308}
309
310impl<T1: Plugin, T2: Plugin, T3: Plugin, T4: Plugin, T5: Plugin> PluginCollection
311 for (T1, T2, T3, T4, T5)
312{
313 fn attach_to_app(self, app: &mut App) {
314 let boxed_plugin1 = Box::new(self.0);
315 let boxed_plugin2 = Box::new(self.1);
316 let boxed_plugin3 = Box::new(self.2);
317 let boxed_plugin4 = Box::new(self.3);
318 let boxed_plugin5 = Box::new(self.4);
319
320 app.internal_add_plugin(boxed_plugin1);
321 app.internal_add_plugin(boxed_plugin2);
322 app.internal_add_plugin(boxed_plugin3);
323 app.internal_add_plugin(boxed_plugin4);
324 app.internal_add_plugin(boxed_plugin5);
325 }
326}
327
328pub trait Plugin: 'static {
330 fn build(&self, _app: &mut App) {}
332
333 fn is_initialized(&self, _app: &App) -> bool {
334 true
335 }
336
337 fn post_initialization(&self, _app: &mut App) {}
338
339 fn type_name(&self) -> &'static str {
340 type_name::<Self>()
341 }
342}
343
344impl std::fmt::Debug for dyn Plugin {
345 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
346 write!(f, "{}", self.type_name())
347 }
348}