Crate generic_state_machine

Source
Expand description

§Summary

A simple library that allows to create Moore or Mealy state machines It is designed around the StateMachine<S,E> type and allows the use of custom transition functions.

§Requirements:

  • All states need to be of the same type S
  • All events (inputs) need to be of the same type E
  • Transition functions are executed over self (to have access to internal lists of states or events) and need to follow the prototype:
     fn(&mut StateMachine<S, E>, E) -> S;
    where input E is the trigger event and the return value is the new state.
  • Output generation is left to the user to allow the implementation to be as generic as possible. You can print or call exernal functions to produce the desired output

§Implement Moore state machine:

  • Define transition functions that calculate the next state and use that to produce any outputs

§Implement Mealy state machine:

  • Define transition functions that calculate the next state and use that together with the input event E to produce any outputs

§A Basic Example of a State Machine (using the asynchronous implementation):

           +------------+
  Event: 1 |            | +----+
           |            V |    | Event: 1
     +->[false]       [true]<--+
     |   | ^            |
     +---+ |            | Event: 0
 Event: 0  +------------+
#[cfg(features = "async")]
#[tokio::test]
async fn state_machine_example() -> Result<()> {
    let mut fsm = AsyncStateMachine::<bool, usize>::new(5);
        fsm.add_states(&mut vec![true, false])
            .await
            .add_transition(true, 0, |_fsm, _event| false)
            .await
            .add_transition(true, 1, |_fsm, _event| true)
            .await
            .add_transition(false, 0, |_fsm, _event| false)
            .await
            .add_transition(false, 1, |_fsm, _event| true)
            .await
            .set_state(false)
            .await;

        fsm.start().await.unwrap();

        println!("My State Machine: {:?}", fsm);

        fsm.push_event(0).await.unwrap();
        assert_eq!(fsm.current_state().await, false);

        fsm.push_event(1).await.unwrap();
        assert_eq!(fsm.current_state().await, true);

        fsm.push_event(1).await.unwrap();
        assert_eq!(fsm.current_state().await, true);

        fsm.push_event(0).await.unwrap();
        assert_eq!(fsm.current_state().await, false);

        fsm.push_event(0).await.unwrap();
        assert_eq!(fsm.current_state().await, false);
}

§A Basic Example of a State Machine (using the primitive type):

           +---->[1]----+
  Event: 1 |            | Event: 2
           |            V
          [3]          [2]
           ^            |
           |            | Event: 3
           +------------+
use generic_state_machine::primitives::StateMachine;

// Define a transition function. It can as general as we want!
fn tf(_fsm: &StateMachine<i32, i32>, event: i32) -> i32 {
match event {
    1 => 1,
    2 => 2,
    3 => 3,
    _ => panic!(), // Invalid transition
    }
}

let mut fsm = StateMachine::<i32, i32>::new();
fsm.add_states(&mut vec![1, 2, 3]);

// We can even use captures as transition functions!
fsm.add_transition(1, 2, |_fsm, _event| {
    // We are in state 1! Go to state 2! Ignore Input!
    2
});

fsm.add_transition(2, 3, tf);
fsm.add_transition(3, 1, tf);
fsm.initial_state(1);

println!("{:?}", fsm);

assert_eq!(2, fsm.execute(2).unwrap());
assert_eq!(3, fsm.execute(3).unwrap());
assert_eq!(1, fsm.execute(1).unwrap());

Modules§

primitives