#state-machine #state #machine #moore #fsm #mealy

generic-state-machine

一个简单的 Rust 库,允许创建通用的或 Moore 或 Mealy 状态机,允许使用自定义的转换函数。

1 个不稳定版本

0.1.0 2023年9月24日

2207算法

MIT 许可证

24KB
313

Coverage Status

摘要

一个简单的库,允许创建 Moore 或 Mealy 状态机。它围绕 StateMachine<S,E> 类型设计,并允许使用自定义的转换函数。

要求

  • 所有状态需要是相同的类型 S
  • 所有事件(输入)需要是相同的类型 E
  • 转换函数在 self 上执行(以访问内部状态或事件列表)并需要遵循原型
     fn(&mut StateMachine<S, E>, E) -> S;
    
    其中输入 E 是触发事件,返回值是新状态。
  • 输出生成留给用户,以允许实现尽可能通用。您可以打印或调用外部函数以生成所需的输出

实现 Moore 状态机

  • 定义转换函数,计算下一个状态,并使用该状态生成任何输出

实现 Mealy 状态机

  • 定义转换函数,计算下一个状态,并使用该状态以及输入事件 E 生成任何输出

异步状态机的基本示例

           +------------+
  Event: 1 |            | +----+
           |            V |    | Event: 1
     +->[false]       [true]<--+
     |   | ^            |
     +---+ |            | Event: 0
 Event: 0  +------------+
use state_machine::state_machine::AsyncStateMachine;

async fn main() -> 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!("State Machine under test: {:?}", 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);
}

状态机的基本示例(使用原始类型)

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

    // Define a transition function. It can as general as we want!
    fn tf(_fsm: &mut 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
    });

    // If you prefer you can chain configuration methods together
    fsm.add_transition(2, 3, tf)
      .add_transition(3, 1, tf)
      .set_state(1);

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

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

依赖关系

~1.2–2.6MB
~55K SLoC