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 日 |
#2353 在 Rust 模式
12,725 每月下载量
用于 rust-fsm
22KB
321 行
一个用于在 Rust 中构建有限状态机的框架和 DSL
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::State
、circuit_breaker::Input
和circuit_breaker::Output
,分别表示状态、输入字母表和输出字母表。 - 类型别名
circuit_breaker::StateMachine
,它扩展为StateMachine<circuit_breaker::Impl>
。
注意,如果规范中没有输出,输出字母表是一个空枚举,并且由于许多Rust属性的技術限制,没有应用于它(例如,derive
、repr
)。
在 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
没有 DSL
state_machine
宏的功能有限(例如,状态不能携带任何附加数据),因此在某些复杂情况下,用户可能想手动编写更复杂的状态机。
构建状态机所需的所有操作是实现 StateMachineImpl
特性,并使用一些提供的包装器(目前只有 StateMachine
)。
您可以在 项目仓库 中看到电路断开状态机的示例。
依赖项
~240–680KB
~16K SLoC