7 个版本 (4 个重大更改)

0.7.0 2024 年 6 月 1 日
0.6.2 2024 年 5 月 11 日
0.6.1 2022 年 12 月 24 日
0.6.0 2021 年 8 月 24 日
0.3.0 2019 年 5 月 22 日

#2353Rust 模式

Download history 2577/week @ 2024-04-13 2262/week @ 2024-04-20 1860/week @ 2024-04-27 2372/week @ 2024-05-04 2802/week @ 2024-05-11 6555/week @ 2024-05-18 5749/week @ 2024-05-25 5484/week @ 2024-06-01 2978/week @ 2024-06-08 2961/week @ 2024-06-15 3381/week @ 2024-06-22 3317/week @ 2024-06-29 4007/week @ 2024-07-06 3073/week @ 2024-07-13 3235/week @ 2024-07-20 1907/week @ 2024-07-27

12,725 每月下载量
用于 rust-fsm

MIT 许可证

22KB
321

一个用于在 Rust 中构建有限状态机的框架和 DSL

Documentation Latest Version

rust-fsm 包提供了一个简单且通用的框架,用于以最小的努力在 Rust 中构建状态机。

此包的核心部分是 StateMachineImpl 特性。此特性允许开发者提供严格的状态机定义,例如指定其

  • 输入字母表 - 状态机作为输入接受的一组实体,并根据它们执行状态转换。
  • 可能的状态 - 此机器可能处于的一组状态。
  • 输出字母表 - 状态机可能作为其工作结果输出的实体集合。
  • 转换函数 - 根据当前状态和提供的输入更改状态机状态的函数。
  • 输出函数 - 根据当前状态和提供的输入从输出字母表中输出内容的函数。
  • 机器的初始状态。

请注意,在实现层面上,此类抽象允许构建任何类型的状态机

  • 通过仅提供输入字母表、状态集和转换函数来构建经典状态机。
  • 通过提供所有上述实体来构建 Mealy 机器。
  • 通过提供不依赖于提供的输入的输出函数来构建 Moore 机器。

功能标志

默认

  • std - 实现 std 环境所需的特性。见下文。
  • dsl - 从 rust-fsm 重新导出 rust-fsm-dsl。建议保留此特性以获得最佳开发体验。

非默认

  • diagram - 在文档字符串中生成Mermaid状态图。见下文。

no_std环境中的使用

该库具有名为std的功能,默认启用。您可能希望将此库导入为rust-fsm = { version = "0.7", default-features = false, features = ["dsl"] },以在no_std环境中使用它。这仅影响错误类型(Error特质仅在std中可用)。

DSL实现的重导出受名为dsl的功能控制,该功能默认启用。

使用方法

最初,此库的设计是为了构建一个易于使用的DSL,用于在其之上定义状态机。使用DSL需要连接一个额外的crate rust-fsm-dsl(这是由于过程宏系统限制所致)。

使用DSL定义状态机

DSL由state_machine宏解析。以下是一个小示例。

use rust_fsm::*;

state_machine! {
    #[derive(Debug)]
    #[repr(C)]
    /// A Circuit Breaker state machine.
    circuit_breaker(Closed)

    Closed(Unsuccessful) => Open [SetupTimer],
    Open(TimerTriggered) => HalfOpen,
    HalfOpen => {
        Successful => Closed,
        Unsuccessful => Open [SetupTimer]
    }
}

此代码示例

  • 定义了一个名为circuit_breaker的状态机;
  • 为它推导了Debug特质。您在这里使用的所有属性(如#[repr(C)])将应用于此宏生成的所有类型。如果您想将属性或文档字符串应用于此宏生成的mod,只需将其放在宏调用之前即可。
  • 将此状态机的初始状态设置为Closed
  • 定义状态转换。例如:在HalfOpen状态下收到Successful输入时,机器必须移动到Closed状态;
  • 定义输出。例如:在Closed状态下收到Unsuccessful时,机器必须输出SetupTimer

可以使用以下方式使用此状态机

// Initialize the state machine. The state is `Closed` now.
let mut machine = circuit_breaker::StateMachine::new();
// Consume the `Successful` input. No state transition is performed.
let _ = machine.consume(&circuit_breaker::Input::Successful);
// Consume the `Unsuccesful` input. The machine is moved to the `Open`
// state. The output is `SetupTimer`.
let output = machine.consume(&circuit_breaker::Input::Unsuccessful).unwrap();
// Check the output
if let Some(circuit_breaker::Output::SetupTimer) = output {
    // Set up the timer...
}
// Check the state
if let circuit_breaker::State::Open = machine.state() {
    // Do something...
}

以下实体被生成

  • 一个空结构circuit_breaker::Impl,它实现了StateMachineImpl特质。
  • 枚举circuit_breaker::Statecircuit_breaker::Inputcircuit_breaker::Output,分别表示状态、输入字母表和输出字母表。
  • 类型别名circuit_breaker::StateMachine,它扩展为StateMachine<circuit_breaker::Impl>

注意,如果规范中没有输出,输出字母表是一个空枚举,并且由于许多Rust属性的技術限制,没有应用于它(例如,deriverepr)。

state_machine 宏中,您必须定义至少一个状态转换。

可见性

您可以使用以下方式指定可见性

use rust_fsm::*;

state_machine! {
    pub CircuitBreaker(Closed)

    Closed(Unsuccessful) => Open [SetupTimer],
    Open(TimerTriggered) => HalfOpen,
    HalfOpen => {
        Successful => Closed,
        Unsuccessful => Open [SetupTimer],
    }
}

默认可见性是私有的。

自定义字母类型

您可以将自己的类型提供作为输入、输出或状态的用途。所有这些都是可选的:您可以使用它们中的一个或全部,根据需要。当前的限制是您必须提供完全限定的类型路径。

use rust_fsm::*;

pub enum Input {
    Successful,
    Unsuccessful,
    TimerTriggered,
}

pub enum State {
    Closed,
    HalfOpen,
    Open,
}

pub enum Output {
    SetupTimer,
}

state_machine! {
    #[state_machine(input(crate::Input), state(crate::State), output(crate::Output))]
    circuit_breaker(Closed)

    Closed(Unsuccessful) => Open [SetupTimer],
    Open(TimerTriggered) => HalfOpen,
    HalfOpen => {
        Successful => Closed,
        Unsuccessful => Open [SetupTimer]
    }
}

图表

state_machine 宏可以使用图表来记录状态机。这由非默认的 diagram 功能控制。图表以 Mermaid 格式生成。此功能将 Mermaid 脚本包含到文档页面中。

要查看实际效果,请下载仓库并运行

cargo doc -p doc-example --open

image

没有 DSL

state_machine 宏的功能有限(例如,状态不能携带任何附加数据),因此在某些复杂情况下,用户可能想手动编写更复杂的状态机。

构建状态机所需的所有操作是实现 StateMachineImpl 特性,并使用一些提供的包装器(目前只有 StateMachine)。

您可以在 项目仓库 中看到电路断开状态机的示例。

依赖项

~240–680KB
~16K SLoC