Rust有限状态机(FSM)库rust-fsm的使用,实现高效状态转换与事件驱动的状态管理
Rust有限状态机(FSM)库rust-fsm的使用,实现高效状态转换与事件驱动的状态管理
rust-fsm
是一个简单通用的框架,用于在Rust中构建状态机,可以最小化开发者的工作量。
核心特性
该库的核心是 StateMachineImpl
特性,它允许开发者严格定义状态机,包括:
- 输入字母表 - 状态机接收的输入集合
- 可能的状态 - 状态机可能处于的状态集合
- 输出字母表 - 状态机工作结果输出的集合
- 转换函数 - 根据当前状态和输入改变状态的函数
- 输出函数 - 基于当前状态和输入从输出字母表中输出结果的函数
- 状态机的初始状态
DSL示例
以下是使用DSL定义状态机的示例:
use rust_fsm::*;
state_machine! {
#[derive(Debug)]
#[repr(C)]
/// 一个断路器状态机
circuit_breaker(Closed)
Closed(Unsuccessful) => Open [SetupTimer],
Open(TimerTriggered) => HalfOpen,
HalfOpen => {
Successful => Closed,
Unsuccessful => Open [SetupTimer]
}
}
这个代码定义了:
- 名为
circuit_breaker
的状态机 - 初始状态为
Closed
- 状态转换规则,例如:在
HalfOpen
状态收到Successful
输入时转移到Closed
状态 - 输出规则,例如:在
Closed
状态收到Unsuccessful
时输出SetupTimer
使用示例:
// 初始化状态机,当前状态为 Closed
let mut machine = circuit_breaker::StateMachine::new();
// 消耗 Successful 输入,不进行状态转换
let _ = machine.consume(&circuit_breaker::Input::Successful);
// 消耗 Unsuccessful 输入,状态转移到 Open,输出 SetupTimer
let output = machine.consume(&circuit_breaker::Input::Unsuccessful).unwrap();
// 检查输出
if let Some(circuit_breaker::Output::SetupTimer) = output {
// 设置定时器...
}
// 检查状态
if let circuit_breaker::State::Open = machine.state() {
// 执行操作...
}
完整示例
以下是一个完整的断路器状态机实现示例:
use rust_fsm::*;
// 定义状态机
state_machine! {
#[derive(Debug)]
pub CircuitBreaker(Closed)
Closed(Unsuccessful) => Open [SetupTimer],
Open(TimerTriggered) => HalfOpen,
HalfOpen => {
Successful => Closed,
Unsuccessful => Open [SetupTimer]
}
}
fn main() {
// 创建状态机实例
let mut machine = CircuitBreaker::StateMachine::new();
// 初始状态应为 Closed
assert!(matches!(machine.state(), CircuitBreaker::State::Closed));
// 处理 Successful 事件 - 应保持 Closed 状态
let output = machine.consume(&CircuitBreaker::Input::Successful);
assert!(output.unwrap().is_none());
assert!(matches!(machine.state(), CircuitBreaker::State::Closed));
// 处理 Unsuccessful 事件 - 应转移到 Open 状态并输出 SetupTimer
let output = machine.consume(&CircuitBreaker::Input::Unsuccessful);
assert!(matches!(output.unwrap(), Some(CircuitBreaker::Output::SetupTimer)));
assert!(matches!(machine.state(), CircuitBreaker::State::Open));
// 处理 TimerTriggered 事件 - 应转移到 HalfOpen 状态
let output = machine.consume(&CircuitBreaker::Input::TimerTriggered);
assert!(output.unwrap().is_none());
assert!(matches!(machine.state(), CircuitBreaker::State::HalfOpen));
// 处理 Successful 事件 - 应返回 Closed 状态
let output = machine.consume(&CircuitBreaker::Input::Successful);
assert!(output.unwrap().is_none());
assert!(matches!(machine.state(), CircuitBreaker::State::Closed));
println!("All state transitions completed successfully!");
}
自定义类型
可以使用自定义类型作为输入、输出或状态:
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]
}
}
安装
在项目目录中运行以下Cargo命令:
cargo add rust-fsm
或在Cargo.toml中添加:
rust-fsm = "0.8.0"
rust-fsm
提供了一种简洁高效的方式来管理复杂的状态逻辑,非常适合需要明确状态转换和事件处理的应用程序。
完整示例demo
以下是一个基于电梯控制系统的完整状态机示例:
use rust_fsm::*;
// 定义电梯状态机
state_machine! {
#[derive(Debug)]
pub Elevator(Idle)
// 状态转换规则
Idle => {
CallUp(FloorSelected) => MovingUp,
CallDown(FloorSelected) => MovingDown
},
MovingUp => {
ReachedFloor => {
AtDestination => Idle,
NotAtDestination => MovingUp [AnnounceFloor]
}
},
MovingDown => {
ReachedFloor => {
AtDestination => Idle,
NotAtDestination => MovingDown [AnnounceFloor]
}
}
}
fn main() {
// 创建电梯状态机实例
let mut elevator = Elevator::StateMachine::new();
// 初始状态应为 Idle
assert!(matches!(elevator.state(), Elevator::State::Idle));
// 处理 CallUp 事件,选择第3层
let output = elevator.consume(&Elevator::Input::CallUp(3));
assert!(output.unwrap().is_none());
assert!(matches!(elevator.state(), Elevator::State::MovingUp));
// 到达第1层(不是目的地)
let output = elevator.consume(&Elevator::Input::ReachedFloor(1));
assert!(matches!(output.unwrap(), Some(Elevator::Output::AnnounceFloor)));
assert!(matches!(elevator.state(), Elevator::State::MovingUp));
// 到达第3层(目的地)
let output = elevator.consume(&Elevator::Input::ReachedFloor(3));
assert!(output.unwrap().is_none());
assert!(matches!(elevator.state(), Elevator::State::Idle));
println!("Elevator simulation completed successfully!");
}
这个示例展示了:
- 电梯的三种状态:空闲(Idle)、上升(MovingUp)和下降(MovingDown)
- 状态转换触发条件:呼叫电梯(CallUp/CallDown)、到达楼层(ReachedFloor)
- 输出动作:到达中间楼层时播报楼层(AnnounceFloor)
- 完整的电梯运行流程模拟
1 回复
Rust有限状态机(FSM)库rust-fsm使用指南
简介
rust-fsm是一个轻量级的Rust有限状态机(FSM)实现库,它提供了简洁的API来定义和管理状态机,支持高效的状态转换和事件驱动的状态管理。这个库特别适合需要明确状态转换逻辑的应用程序,如协议实现、游戏AI、业务流程等场景。
基本概念
- 状态(State): 系统所处的特定模式或条件
- 事件(Event): 触发状态转换的动作或输入
- 转换(Transition): 从一个状态到另一个状态的变化
- 动作(Action): 状态转换时执行的操作
安装
在Cargo.toml中添加依赖:
[dependencies]
rust-fsm = "0.6"
基本使用方法
1. 定义状态机
use rust_fsm::*;
fsm! {
enum LightSwitch {
// 初始状态
Initial = Off,
// 状态定义
Off,
On,
// 转换定义
Off => On => toggle,
On => Off => toggle,
}
}
2. 使用状态机
fn main() {
// 创建状态机实例
let mut fsm: StateMachine<LightSwitch> = StateMachine::new();
// 获取当前状态
println!("当前状态: {:?}", fsm.state()); // Off
// 触发事件
fsm.trigger(&LightSwitchInput::toggle()).unwrap();
println!("当前状态: {:?}", fsm.state()); // On
// 再次触发
fsm.trigger(&LightSwitchInput::toggle()).unwrap();
println!("当前状态: {:?}", fsm.state()); // Off
}
高级功能
1. 带数据的转换
fsm! {
enum Counter {
Initial = Zero,
Zero,
One,
Two,
Zero => One => increment(u32),
One => Two => increment(u32),
Two => Zero => reset,
}
}
fn main() {
let mut fsm: StateMachine<Counter> = StateMachine::new();
// 带数据的转换
fsm.trigger(&CounterInput::increment(42)).unwrap();
println!("当前状态: {:?}", fsm.state()); // One
fsm.trigger(&CounterInput::increment(10)).unwrap();
println!("当前状态: {:?}", fsm.state()); // Two
fsm.trigger(&CounterInput::reset()).unwrap();
println!("当前状态: {:?}", fsm.state()); // Zero
}
2. 状态进入/退出动作
fsm! {
enum Door {
Initial = Closed,
Closed,
Open,
Closed => Open => open,
Open => Closed => close,
impl {
fn on_enter_closed(&mut self) {
println!("门已关闭");
}
fn on_exit_closed(&mut self) {
println!("门即将打开");
}
fn on_enter_open(&mut self) {
println!("门已打开");
}
}
}
}
3. 条件转换
fsm! {
enum AuthSystem {
Initial = LoggedOut,
LoggedOut,
LoggedIn,
LoggedOut => LoggedIn => login(username: String, password: String)
if |input| input.password == "correct",
LoggedIn => LoggedOut => logout,
}
}
fn main() {
let mut fsm: StateMachine<AuthSystem> = StateMachine::new();
// 密码不正确会失败
let result = fsm.trigger(&AuthSystemInput::login("user".to_string(), "wrong".to_string()));
assert!(result.is_err());
// 密码正确会成功
fsm.trigger(&AuthSystemInput::login("user".to_string(), "correct".to_string())).unwrap();
println!("当前状态: {:?}", fsm.state()); // LoggedIn
}
完整示例:交通信号灯状态机
use rust_fsm::*;
// 定义交通信号灯状态机
fsm! {
enum TrafficLight {
Initial = Red,
Red,
Green,
Yellow,
Red => Green => next,
Green => Yellow => next,
Yellow => Red => next,
impl {
fn on_enter_red(&mut self) {
println!("红灯亮 - 禁止通行");
}
fn on_enter_green(&mut self) {
println!("绿灯亮 - 允许通行");
}
fn on_enter_yellow(&mut self) {
println!("黄灯亮 - 准备停止");
}
}
}
}
fn main() {
let mut light = StateMachine::new();
// 初始状态
println!("初始状态: {:?}", light.state());
// 状态转换循环
for _ in 0..6 {
light.trigger(&TrafficLightInput::next()).unwrap();
println!("当前状态: {:?}", light.state());
}
}
性能考虑
rust-fsm设计非常高效:
- 状态转换是O(1)操作
- 无堆分配(no_std兼容)
- 编译时检查状态转换有效性
总结
rust-fsm提供了一种类型安全且高效的方式来管理复杂的状态转换逻辑。通过宏定义状态机,编译器可以验证所有可能的状态转换,避免运行时错误。它特别适合需要严格状态管理的场景,如协议实现、UI状态管理或业务流程控制。
对于更复杂的需求,可以考虑结合tokio等异步运行时实现事件驱动的状态机,或者使用enum_dispatch等技术来为不同状态实现不同的行为。