#![warn(missing_docs)]
use std::marker::PhantomData;
#[cfg(test)]
mod tests;
pub type DynMachine<A, E, F> = StateMachine<A, E, F, Box<DynState<A, E, F>>>;
pub type DynResult<A, E, F> = Result<Trans<Box<DynState<A, E, F>>>, E>;
pub trait DynState<A, E, F> {
fn start(&mut self, _args: A) -> DynResult<A, E, F> {
Ok(Trans::None)
}
fn resume(&mut self, _args: A) {}
fn pause(&mut self, _args: A) {}
fn stop(&mut self, _args: A) {}
fn update(&mut self, _args: A) -> DynResult<A, E, F> {
Ok(Trans::None)
}
fn fixed_update(&mut self, _args: A) -> DynResult<A, E, F> {
Ok(Trans::None)
}
fn event(&mut self, _args: A, _event: F) -> DynResult<A, E, F> {
Ok(Trans::None)
}
}
pub struct Ref<A: ?Sized> {
marker: PhantomData<A>,
}
pub trait State<A, E, F>: Sized {
fn start(&mut self, _args: A) -> Result<Trans<Self>, E> {
Ok(Trans::None)
}
fn resume(&mut self, _args: A) {}
fn pause(&mut self, _args: A) {}
fn stop(&mut self, _args: A) {}
fn update(&mut self, _args: A) -> Result<Trans<Self>, E> {
Ok(Trans::None)
}
fn fixed_update(&mut self, _args: A) -> Result<Trans<Self>, E> {
Ok(Trans::None)
}
fn event(&mut self, _args: A, _event: F) -> Result<Trans<Self>, E> {
Ok(Trans::None)
}
}
impl<A, E, F> State<A, E, F> for Box<DynState<A, E, F>> {
fn start(&mut self, args: A) -> Result<Trans<Self>, E> {
self.as_mut().start(args)
}
fn resume(&mut self, args: A) {
self.as_mut().resume(args);
}
fn pause(&mut self, args: A) {
self.as_mut().pause(args);
}
fn stop(&mut self, args: A) {
self.as_mut().stop(args);
}
fn update(&mut self, args: A) -> Result<Trans<Self>, E> {
self.as_mut().update(args)
}
fn fixed_update(&mut self, args: A) -> Result<Trans<Self>, E> {
self.as_mut().fixed_update(args)
}
fn event(&mut self, args: A, event: F) -> Result<Trans<Self>, E> {
self.as_mut().event(args, event)
}
}
pub struct StateMachine<A, E, F, S> {
marker: PhantomData<(A, E, F)>,
running: bool,
stack: Vec<S>,
}
impl<A, E, F, S> StateMachine<A, E, F, S> {
pub fn new(initial: S) -> Self {
StateMachine {
marker: PhantomData,
running: false,
stack: vec![initial],
}
}
pub fn running(&self) -> bool {
self.running
}
fn assert_running(&self) {
assert!(self.running, "State machine not running");
}
fn last(&mut self) -> &mut S {
self.stack.last_mut().unwrap()
}
}
macro_rules! def_machine {
( $param:ty, $clone:ident ) => {
pub fn start(&mut self, args: $param) -> Result<(), E> {
if !self.running {
let trans = self.last().start($clone!(args))?;
self.running = true;
self.handle($clone!(args), trans)?;
Ok(())
} else {
panic!("Running already")
}
}
pub fn update(&mut self, args: $param) -> Result<(), E> {
self.assert_running();
let trans = self.last().update($clone!(args))?;
self.handle($clone!(args), trans)
}
pub fn fixed_update(&mut self, args: $param) -> Result<(), E> {
self.assert_running();
let trans = self.last().fixed_update($clone!(args))?;
self.handle($clone!(args), trans)
}
pub fn event(&mut self, args: $param, event: F) -> Result<(), E> {
self.assert_running();
let trans = self.last().event($clone!(args), event)?;
self.handle($clone!(args), trans)
}
pub fn stop(&mut self, args: $param) {
self.assert_running();
if let Some(s) = self.stack.last_mut() {
s.pause($clone!(args));
}
while let Some(mut s) = self.stack.pop() {
s.stop($clone!(args));
}
self.running = false;
}
fn handle(&mut self, args: $param, trans: Trans<S>) -> Result<(), E> {
match trans {
Trans::Push(mut s) => {
self.last().pause($clone!(args));
let trans = s.start($clone!(args))?;
self.handle($clone!(args), trans)?;
s.resume($clone!(args));
self.stack.push(s);
Ok(())
}
Trans::Switch(mut s) => {
{
let old = self.last();
old.pause($clone!(args));
old.stop($clone!(args));
}
let trans = s.start($clone!(args))?;
self.handle($clone!(args), trans)?;
s.resume($clone!(args));
*self.last() = s;
Ok(())
}
Trans::Pop => {
let mut old = self.stack.pop().unwrap();
old.pause($clone!(args));
old.stop($clone!(args));
let resumed = if let Some(s) = self.stack.last_mut() {
s.resume($clone!(args));
true
} else {
false
};
if !resumed {
self.stop($clone!(args));
}
Ok(())
}
Trans::None => Ok(()),
Trans::Quit => {
self.stop($clone!(args));
Ok(())
}
}
}
};
}
macro_rules! pass_on {
($a:ident) => {$a};
}
macro_rules! clone {
($a:ident) => {{Clone::clone(& $a)}};
}
impl<A, E, F, S> StateMachine<Ref<A>, E, F, S>
where
A: ?Sized,
S: for<'a> State<&'a mut A, E, F>,
{
def_machine!(&mut A, pass_on);
}
impl<A, E, F, S> StateMachine<A, E, F, S>
where
A: Clone,
S: State<A, E, F>,
{
def_machine!(A, clone);
}
impl<A, E, F, S> Default for StateMachine<A, E, F, S>
where
S: Default,
{
fn default() -> Self {
StateMachine::new(Default::default())
}
}
pub type StateMachineRef<A, E, F, S> = StateMachine<Ref<A>, E, F, S>;
pub enum Trans<S> {
Push(S),
Switch(S),
Pop,
None,
Quit,
}