#[macro_export]
#[doc(hidden)] macro_rules! __define_state_machine_common {
(
$name:ident,
{ $($state:ident),* },
{ $($input:ident),* },
$initial:ident,
{ $( $from:ident + $inp:ident => $to:ident ),* }
) => {
#[derive(Debug, Clone, Hash, PartialEq, Eq)]
pub enum State {
$($state),*
}
#[derive(Debug, Clone, Hash, PartialEq, Eq)]
pub enum Input {
$($input),*
}
impl std::fmt::Display for State {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
$(State::$state => write!(f, stringify!($state)),)*
}
}
}
impl From<&str> for State {
fn from(s: &str) -> Self {
match s {
$(stringify!($state) => State::$state,)*
_ => panic!("Invalid state: {}", s),
}
}
}
impl std::fmt::Display for Input {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
$(Input::$input => write!(f, stringify!($input)),)*
}
}
}
impl From<&str> for Input {
fn from(s: &str) -> Self {
match s {
$(stringify!($input) => Input::$input,)*
_ => panic!("Invalid input: {}", s),
}
}
}
pub struct $name;
impl $crate::StateMachine for $name {
type State = State;
type Input = Input;
fn states() -> Vec<Self::State> {
vec![$(State::$state),*]
}
fn inputs() -> Vec<Self::Input> {
vec![$(Input::$input),*]
}
fn initial_state() -> Self::State {
State::$initial
}
fn state_name(state: &Self::State) -> String {
format!("{:?}", state)
}
fn input_name(input: &Self::Input) -> String {
format!("{:?}", input)
}
fn valid_inputs(state: &Self::State) -> Vec<Self::Input> {
let mut inputs = Vec::new();
$(
if matches!(state, State::$from) {
inputs.push(Input::$inp);
}
)*
inputs
}
fn next_state(state: &Self::State, input: &Self::Input) -> Option<Self::State> {
#[allow(unreachable_patterns)]
match (state, input) {
$(
(State::$from, Input::$inp) => Some(State::$to),
)*
_ => None,
}
}
}
};
}
#[macro_export]
#[doc(hidden)]
macro_rules! __define_state_machine_serde {
({ $($state:ident),* }, { $($input:ident),* }) => {
impl serde::Serialize for State {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: serde::Serializer,
{
match self {
$(State::$state => serializer.serialize_str(stringify!($state)),)*
}
}
}
impl<'de> serde::Deserialize<'de> for State {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: serde::Deserializer<'de>,
{
let s = String::deserialize(deserializer)?;
match s.as_str() {
$(stringify!($state) => Ok(State::$state),)*
_ => Err(serde::de::Error::custom(format!("Unknown state: {}", s))),
}
}
}
impl serde::Serialize for Input {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: serde::Serializer,
{
match self {
$(Input::$input => serializer.serialize_str(stringify!($input)),)*
}
}
}
impl<'de> serde::Deserialize<'de> for Input {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: serde::Deserializer<'de>,
{
let s = String::deserialize(deserializer)?;
match s.as_str() {
$(stringify!($input) => Ok(Input::$input),)*
_ => Err(serde::de::Error::custom(format!("Unknown input: {}", s))),
}
}
}
};
}
#[cfg(feature = "serde")]
#[macro_export]
macro_rules! define_state_machine {
(
name: $name:ident,
states: { $($state:ident),* $(,)? },
inputs: { $($input:ident),* $(,)? },
initial: $initial:ident,
transitions: {
$(
$from:ident + $inp:ident => $to:ident
),* $(,)?
}
) => {
$crate::__define_state_machine_common!(
$name,
{ $($state),* },
{ $($input),* },
$initial,
{ $( $from + $inp => $to ),* }
);
$crate::__define_state_machine_serde!(
{ $($state),* },
{ $($input),* }
);
};
}
#[cfg(not(feature = "serde"))]
#[macro_export]
macro_rules! define_state_machine {
(
name: $name:ident,
states: { $($state:ident),* $(,)? },
inputs: { $($input:ident),* $(,)? },
initial: $initial:ident,
transitions: {
$(
$from:ident + $inp:ident => $to:ident
),* $(,)?
}
) => {
$crate::__define_state_machine_common!(
$name,
{ $($state),* },
{ $($input),* },
$initial,
{ $( $from + $inp => $to ),* }
);
};
}