use crate::ecs::events::lifecycle::{LifecycleRequested, ShutdownRequest};
use bevy::{
app::AppExit,
prelude::{MessageReader, MessageWriter, ResMut, Resource},
};
#[derive(Clone, Copy, Debug, Default, Eq, PartialEq, Resource)]
pub(super) struct LifecycleState {
phase: LifecyclePhase,
}
impl LifecycleState {
const fn request_shutdown(&mut self, request: ShutdownRequest) {
if matches!(self.phase, LifecyclePhase::Running) {
self.phase = LifecyclePhase::ShuttingDown(request);
}
}
const fn shutdown_request(self) -> Option<ShutdownRequest> {
match self.phase {
LifecyclePhase::Running => None,
LifecyclePhase::ShuttingDown(request) => Some(request),
}
}
}
#[derive(Clone, Copy, Debug, Default, Eq, PartialEq)]
enum LifecyclePhase {
#[default]
Running,
ShuttingDown(ShutdownRequest),
}
pub(super) fn apply_lifecycle_requests(
mut requests: MessageReader<LifecycleRequested>,
mut lifecycle: ResMut<LifecycleState>,
mut app_exit: MessageWriter<AppExit>,
) {
for request in requests.read() {
match request {
LifecycleRequested::Shutdown(shutdown) => {
lifecycle.request_shutdown(*shutdown);
}
}
}
if let Some(request) = lifecycle.shutdown_request() {
let _sent = app_exit.write(request.app_exit());
}
}
#[cfg(test)]
mod tests {
use super::{LifecyclePhase, LifecycleState};
use crate::ecs::events::lifecycle::{ShutdownReason, ShutdownRequest};
#[test]
fn shutdown_state_is_terminal_after_first_request() {
let mut state = LifecycleState::default();
let request = ShutdownRequest::successful_user_command();
state.request_shutdown(request);
state.request_shutdown(request);
assert_eq!(state.phase, LifecyclePhase::ShuttingDown(request));
assert_eq!(state.shutdown_request(), Some(request));
assert_eq!(request.reason(), ShutdownReason::UserCommand);
}
}