use crate::state::BoxState;
use crate::trans::Trans;
#[derive(Default)]
pub struct Stack<D> {
stack: Vec<BoxState<D>>,
}
impl<D> Stack<D> {
#[must_use]
pub fn new() -> Self {
Self { stack: vec![] }
}
}
impl<D> Stack<D> {
#[must_use]
pub fn is_running(&self) -> bool {
!self.stack.is_empty()
}
#[must_use]
pub fn len(&self) -> usize {
self.stack.len()
}
#[must_use]
pub fn is_empty(&self) -> bool {
self.stack.is_empty()
}
}
impl<D> Stack<D> {
pub fn push(&mut self, data: &mut D, mut state: BoxState<D>) {
if let Some(curr_state) = self.stack.last_mut() {
curr_state.on_pause(data);
}
state.on_start(data);
self.stack.push(state);
}
pub fn pop(&mut self, data: &mut D) {
if let Some(mut curr_state) = self.stack.pop() {
curr_state.on_stop(data);
}
if let Some(state) = self.stack.last_mut() {
state.on_resume(data);
}
}
pub fn quit(&mut self, data: &mut D) {
while let Some(mut state) = self.stack.pop() {
state.on_stop(data);
}
}
}
impl<D> Stack<D> {
#[inline]
pub fn replace(&mut self, data: &mut D, state: BoxState<D>) {
self.pop(data);
self.push(data, state);
}
#[inline]
pub fn isolate(&mut self, data: &mut D, state: BoxState<D>) {
self.quit(data);
self.push(data, state);
}
}
impl<D> Stack<D> {
#[inline]
fn transition(&mut self, data: &mut D, trans: Trans<D>) {
match trans {
Trans::Push(state) => self.push(data, state),
Trans::Pop => self.pop(data),
Trans::Replace(state) => self.replace(data, state),
Trans::Isolate(state) => self.isolate(data, state),
Trans::None => (),
Trans::Quit => self.quit(data),
};
}
pub fn tick(&mut self, data: &mut D) {
let mut transitions: Vec<Trans<D>> = vec![];
self.stack.iter_mut().for_each(|state| {
transitions.push(state.on_shadow_tick(data))
});
if let Some(state) = self.stack.last_mut() {
transitions.push(state.on_tick(data));
}
transitions.into_iter().for_each(|trans| {
self.transition(data, trans);
});
}
}