In the C family of languages I usually implement a state machine as a series of if else statements and enums, where if statements check in which state the machine is and the bodies execute state transitions, for example this:
if(current_left_state == GLFW_PRESS && !left_pressed)
{
left_pressed = true;
return MouseInputState::LEFT_DOWN;
}
if(current_left_state == GLFW_PRESS && left_pressed)
{
left_pressed = true;
return MouseInputState::LEFT_DRAG;
}
if(current_left_state == GLFW_RELEASE && left_pressed)
{
left_pressed = false;
return MouseInputState::LEFT_UP;
}
if(current_right_state == GLFW_PRESS && !right_pressed)
{
right_pressed = true;
return MouseInputState::RIGHT_DOWN;
}
Rust has a lot of idiomatic sugar which is nice, I was wondering if there is a way to use rust's syntactic sugar to make cleaner state machines.
Like, there has got to be a better way than this:
MouseState::NoAction =>
{
if *button == glfw::MouseButtonLeft && *action == glfw::Action::Press
{
return MouseState::LeftDown;
}
if *button == glfw::MouseButtonRight && *action == glfw::Action::Press
{
return MouseState::RightDown;
}
return MouseState::NoAction;
}
MouseState::LeftDown =>
{
if *button == glfw::MouseButtonLeft && *action == glfw::Action::Release
{
return MouseState::LeftUp;
}
return MouseState::LeftDrag;
}
MouseState::LeftDrag =>
{
if *button == glfw::MouseButtonLeft && *action == glfw::Action::Release
{
return MouseState::LeftUp;
}
return MouseState::LeftDrag;
}
MouseState::LeftUp =>
{
if *button == glfw::MouseButtonLeft && *action == glfw::Action::Press
{
return MouseState::LeftUp;
}
return MouseState::NoAction;
}
For really clean state machines, you can match on tuples:
let next_state = match (current_state, button, action) => {
(MouseState::NoAction, glfw::MouseButtonLeft, glfw::Action::Press) => MouseState::LeftDown,
(MouseState::NoAction, glfw::MouseButtonRight, glfw::Action::Press) => MouseState::RightDown,
(MouseState::NoAction, _, _) => MouseState::RightDown,
(MouseState::LeftDown, glfw::MouseButtonLeft, glfw::Action::Release) => MouseState::LeftUp,
(MouseState::LeftDown, _, _) => MouseState::LeftDrag,
(MouseState::LeftDrag, glfw::MouseButtonLeft, glfw::Action::Release) => MouseState::LeftUp,
(MouseState::LeftDrag, _, _) => MouseState::LeftDrag,
(MouseState::LeftUp, glfw::MouseButtonLeft, glfw::Action::Press) => MouseState::LeftUp,
(MouseState::LeftUp, _, _) => MouseState::NoAction,
_ => MouseState::NoAction,
}
Depending on your preference, you can consolidate the branches with the same result using the |
pattern.