#状态机 #有限状态机 #dot #fsm #转换 #定义 #fsmentry

fsmentry-core

具有入口API和数据存储的有限状态机

3个版本

0.1.2 2023年10月8日
0.1.1 2023年10月8日
0.1.0 2023年10月8日

#1956过程宏


用于 2 crate

MIT/Apache

47KB
849

fsmentry

有限状态机(FSM)的代码生成器,具有以下特性

  • 将您的机器定义为图,例如 DOT
  • 一个 entry API来转换状态机。
  • 非法状态和转换无法表示。
  • 状态可以包含数据。
  • 支持自定义 #[derive(..)]
  • #![no_std] 支持。
  • 在文档中包含状态机的内联SVG图。
// define the machine.
// you can also use the DOT language if you prefer.
fsmentry::dsl! {
    /// This is a state machine for a traffic light
    // Documentation on nodes and states will appear in the generated code
    pub TrafficLight {
        Red; // this is a state
        Green: String; // this state has data inside it.

        /// Cars speed up
        // this documentation is shared among all the edges
        Red -> RedAmber -> Green;
        //     ^ states are implicitly created

        /// Cars slow down
        Green -> Amber -"make sure you stop!"-> Red;
        //             ^ this documentation is for this edge only
    }
}

use traffic_light::{TrafficLight, Entry};

// instantiate the machine
let mut machine = TrafficLight::new(traffic_light::State::Red);
loop {
    match machine.entry() {
        Entry::Red(it) => it.red_amber(), // transition the state machine
        // when you transition to a state with data,
        // you must provide the data
        Entry::RedAmber(it) => it.green(String::from("this is some data")),
        Entry::Green(mut it) => {
            // you can inspect or mutate the data in a state...
            let data: &String = it.get();
            let data: &mut String = it.get_mut();
            // ...and you get it back when you transition out of a state
            let data: String = it.amber();
        },
        Entry::Amber(it) => break,
    }
}

Cargo功能

  • macros (默认): 包含 [dot] 和 [dsl] 宏。
  • svg (默认): 如果可用,宏将调用 dot,并生成文档中的状态机图。
  • std (默认): 包括 FSMGenerator,用于自定义代码生成工具。
  • cli: 这不会影响库,但如果您
    cargo install fsmentry --features=cli
    
    您将获得一个可用的 fsmentry 二进制文件,您可以使用它来生成代码。

高级使用

fsmentry::dsl! {
    #[derive(Clone, Debug, derive_quickcheck_arbitrary::Arbitrary)] // attach `#[derive(..)]`s here
    pub MyStateMachine { .. }
}
use my_state_machine::{MyStateMachine, State, Entry};
// ^ A module with matching publicity is generated for the state machine.
//   The `#[derive(..)]`s apply to the `State` and the `MyStateMachine` items.

let mut machine = MyStateMachine::arbitrary(g); // we can use derived traits!

// you can also inspect and mutate the state yourself.
let state: &State = machine.state();
let state: &mut State = machine.state_mut();

match machine.entry() {
    // states with no transitions and no data are empty entries
    Entry::DeadEnd => {},
    // states with no transitions give you the data
    Entry::DeadEndWithData(data) => {
        let _: &mut String = data;
    },
    Entry::WithTransitions(handle) => {
        // otherwise, you get a struct which allows you to transition the machine.
        // (It will have getters for data as appropriate).
        handle.dead_end();
    }
    // ...
}

分层状态机

fsmentry 对于子状态机不需要特殊考虑 - 只需在相关节点上存储一个!以下是来自 statig crate 的示例

┌─────────────────────────┐
│         Blinking        │🞀─────────┐
│    ┌───────────────┐    │          │
│ ┌─🞂│     LedOn     │──┐ │  ┌───────────────┐
│ │  └───────────────┘  │ │  │  NotBlinking  │
│ │  ┌───────────────┐  │ │  └───────────────┘
│ └──│     LedOff    │🞀─┘ │          🞁
│    └───────────────┘    │──────────┘
└─────────────────────────┘
fsmentry::dsl! { // the outer state machine
    pub Webcam {
        NotBlinking -> Blinking -> NotBlinking;
        Blinking: super::led::Led; // The `Blinking` state contains a state machine
    }
}

fsmentry::dsl! { // the inner state machine
    pub Led {
        LedOn -> LedOff -> LedOn;
    }
}

let mut machine = webcam::Webcam::new(webcam::State::NotBlinking);
loop {
    match machine.entry() { // transition the outer machine
        webcam::Entry::Blinking(mut webcam) => match webcam.get_mut().entry() { // transition the inner machine
            led::Entry::LedOff(it) => it.led_on(),
            led::Entry::LedOn(it) => {
                it.led_off();
                webcam.not_blinking();
            }
        },
        webcam::Entry::NotBlinking(webcam) => {
            webcam.blinking(led::Led::new(led::State::LedOff))
        }
    }
}

与其他状态机库的比较

crate 非法状态/转换无法表示 状态包含数据 状态机定义 注释
fsmentry 图表
sm 状态,事件,转换
rust-fsm 是(手动) 状态,事件,转换
finny 构建器
sfsm 状态和转换
statig ? ? ? 复杂的API!
sad_machine 状态,事件,转换
机器 状态,事件,转换

依赖项

~7MB
~31K SLoC