pub enum EmptyStateData {}
pub struct StateCallback<OWNER, STATEDATA = EmptyStateData> {
pub enter: Option<fn(&mut OWNER)>,
pub exit: Option<fn(&mut OWNER)>,
pub statedata: Option<STATEDATA>,
}
impl<OWNER, STATEDATA> StateCallback<OWNER, STATEDATA> {
pub fn new(
enter: Option<fn(&mut OWNER)>,
exit: Option<fn(&mut OWNER)>,
statedata: Option<STATEDATA>,
) -> Self {
StateCallback {
enter: enter,
exit: exit,
statedata: statedata,
}
}
}
pub trait StateSelector<OWNER, STATEDATA = EmptyStateData> {
fn select(&self) -> StateCallback<OWNER, STATEDATA>;
}
pub struct StateMachine<STATE> {
pub current_state: Option<STATE>,
pub in_transition : bool
}
impl<STATE: PartialEq> StateMachine<STATE> {
pub fn new() -> StateMachine<STATE> {
StateMachine {
current_state: None,
in_transition: false
}
}
pub fn is_in(&self, state: Option<STATE>) -> bool {
if let Some(c) = &self.current_state {
if let Some(s) = state {
return *c == s;
} else {
return false;
}
} else {
if let Some(_s) = state {
return false;
} else {
return true;
}
}
}
}
pub fn get_statedata<STATEDATA, OWNER, STATE: StateSelector<OWNER, STATEDATA>>(
state_machine: &StateMachine<STATE>,
) -> Option<STATEDATA> {
if let Some(c) = &state_machine.current_state {
return c.select().statedata;
}
return None;
}
#[macro_export]
macro_rules! state_machine {
($owner_type:ident , $state_type:ident {$({$state_name: ident , $enter: expr , $exit: expr}),*} ) => {
#[derive(PartialEq)]
#[derive(Clone)]
#[derive(Debug)]
enum $state_type {
$($state_name),*
}
impl StateSelector<$owner_type> for $state_type {
fn select(&self) -> StateCallback<$owner_type> {
match self {
$($state_type::$state_name => StateCallback::new($enter, $exit, None)),*
}
}
}
};
($owner_type:ident , $state_data:ident , $state_type:ident {$({$state_name: ident , $enter: expr , $exit: expr, $data: expr}),*} ) => {
#[derive(PartialEq)]
#[derive(Clone)]
#[derive(Debug)]
enum $state_type {
$($state_name),*
}
impl StateSelector<$owner_type, $state_data> for $state_type {
fn select(&self) -> StateCallback<$owner_type, $state_data> {
match self {
$($state_type::$state_name => StateCallback::new($enter, $exit, $data)),*
}
}
}
};
}
#[macro_export]
macro_rules! transition {
($owner:expr, $state_machine:ident , $state:expr) => {{
let mut result = false;
if ($owner.$state_machine.in_transition == false ) {
$owner.$state_machine.in_transition = true;
if let Some(s) = &$owner.state_machine.current_state {
if let Some(c) = s.select().exit {
(c)($owner);
}
}
$owner.$state_machine.current_state = $state;
if let Some(s) = &$owner.state_machine.current_state {
if let Some(c) = s.select().enter {
(c)($owner);
}
}
$owner.$state_machine.in_transition = false;
result = true;
}
result
}};
}