Rust插件库sm的使用:高性能状态机库sm实现轻量级状态管理与转换
Rust插件库sm的使用:高性能状态机库sm实现轻量级状态管理与转换
SM是一个旨在提供安全、快速和简单的状态机库。
- 安全 - Rust的类型系统、所有权模型和详尽模式匹配可防止您误用状态机
- 快速 - 零运行时开销,机器是100%静态的,所有验证都在编译时完成
- 简单 - 五个特性,一个可选声明性宏,仅控制流,不附加业务逻辑
快速示例
extern crate sm;
use sm::sm;
sm! {
Lock {
InitialStates { Locked }
TurnKey {
Locked => Unlocked
Unlocked => Locked
}
Break {
Locked, Unlocked => Broken
}
}
}
fn main() {
use Lock::*;
let lock = Machine::new(Locked);
let lock = lock.transition(TurnKey);
assert_eq!(lock.state(), Unlocked);
assert_eq!(lock.trigger().unwrap(), TurnKey);
}
完整示例代码
下面是一个更完整的状态机示例,展示了如何使用sm库创建和管理状态机:
extern crate sm;
use sm::sm;
// 定义一个电梯状态机
sm! {
Elevator {
InitialStates { Idle }
Call {
Idle => Moving
Moving => Moving // 已经在移动时再次按呼叫按钮不影响状态
}
Arrive {
Moving => Idle
}
Emergency {
Idle, Moving => EmergencyStop
}
}
}
fn main() {
use Elevator::*;
// 创建初始状态为Idle的电梯
let mut elevator = Machine::new(Idle);
println!("初始状态: {:?}", elevator.state());
// 呼叫电梯
elevator = elevator.transition(Call);
println!("呼叫后状态: {:?}", elevator.state());
println!("触发事件: {:?}", elevator.trigger().unwrap());
// 到达楼层
elevator = elevator.transition(Arrive);
println!("到达后状态: {:?}", elevator.state());
// 紧急停止
elevator = elevator.transition(Call); // 先移动到Moving状态
elevator = elevator.transition(Emergency);
println!("紧急停止后状态: {:?}", elevator.state());
// 尝试从EmergencyStop状态呼叫电梯
// 这将无法编译,因为状态机定义中没有从EmergencyStop到其他状态的转换
// elevator = elevator.transition(Call); // 编译错误
}
这个示例展示了:
- 定义了一个电梯状态机,有Idle、Moving和EmergencyStop三种状态
- 定义了Call、Arrive和Emergency三种转换事件
- 展示了如何创建状态机实例并进行状态转换
- 演示了状态机如何防止无效的状态转换(最后一行注释掉的代码会引发编译错误)
sm库的主要优势在于它能在编译时捕获所有可能的状态转换错误,确保您的状态机逻辑始终正确。
1 回复
Rust插件库sm的使用:高性能状态机库sm实现轻量级状态管理与转换
介绍
sm
是一个轻量级、高性能的Rust状态机库,它提供了一种简单而强大的方式来实现状态模式。这个库特别适合需要管理复杂状态转换的系统,如游戏开发、网络协议实现或用户界面交互。
主要特点:
- 极简API设计
- 零运行时开销
- 编译时状态转换验证
- 无动态分配
- 支持
no_std
环境
安装
在Cargo.toml中添加依赖:
[dependencies]
sm = "0.5"
基本使用方法
1. 定义状态和事件
use sm::sm;
sm! {
TrafficLight {
InitialStates { Red }
Green {
TimerElapsed => Yellow
}
Yellow {
TimerElapsed => Red
}
Red {
TimerElapsed => Green
}
}
}
2. 使用状态机
fn main() {
use TrafficLight::*;
// 创建状态机,初始状态为Red
let mut sm = Machine::new(Red);
// 当前状态
println!("Current state: {:?}", sm.state()); // 输出: Red
// 触发事件
sm = sm.trigger(TimerElapsed).unwrap();
println!("After TimerElapsed: {:?}", sm.state()); // 输出: Green
sm = sm.trigger(TimerElapsed).unwrap();
println!("After TimerElapsed: {:?}", sm.state()); // 输出: Yellow
sm = sm.trigger(TimerElapsed).unwrap();
println!("After TimerElapsed: {:?}", sm.state()); // 输出: Red
}
完整示例
下面是一个完整的状态机实现示例,模拟一个简单的下载器状态管理:
use sm::sm;
// 定义下载状态机
sm! {
Downloader {
InitialStates { Idle }
// 空闲状态
Idle {
StartDownload { url: String } => Downloading
}
// 下载中状态
Downloading {
Pause => Paused,
Complete => Completed,
Error => ErrorState
}
// 暂停状态
Paused {
Resume => Downloading,
Cancel => Idle
}
// 完成状态
Completed {
Reset => Idle
}
// 错误状态
ErrorState {
Retry => Downloading,
Cancel => Idle
}
}
}
// 实现状态进入/退出动作
impl Downloader {
fn on_enter(&self) {
match self.state() {
Downloader::Idle => println!("进入空闲状态"),
Downloader::Downloading => println!("开始下载..."),
Downloader::Paused => println!("下载已暂停"),
Downloader::Completed => println!("下载完成!"),
Downloader::ErrorState => println!("下载出错"),
}
}
}
fn main() {
use Downloader::*;
// 创建状态机实例
let mut sm = Machine::new(Idle);
sm.on_enter(); // 输出: 进入空闲状态
// 开始下载
sm = sm.trigger(StartDownload {
url: "https://example.com/file".to_string()
}).unwrap();
sm.on_enter(); // 输出: 开始下载...
// 模拟下载暂停
sm = sm.trigger(Pause).unwrap();
sm.on_enter(); // 输出: 下载已暂停
// 继续下载
sm = sm.trigger(Resume).unwrap();
sm.on_enter(); // 输出: 开始下载...
// 下载完成
sm = sm.trigger(Complete).unwrap();
sm.on_enter(); // 输出: 下载完成!
// 重置状态机
sm = sm.trigger(Reset).unwrap();
sm.on_enter(); // 输出: 进入空闲状态
}
高级用法
带数据的转换
sm! {
AuthSystem {
InitialStates { LoggedOut }
LoggedOut {
Login { username: String, password: String } => LoggedIn if |login| login.password == "secret"
}
LoggedIn {
Logout => LoggedOut
}
}
}
并行状态机
sm! {
MediaPlayer {
InitialStates { Stopped }
Stopped {
Play => Playing
}
Playing {
Pause => Paused,
Stop => Stopped
}
Paused {
Play => Playing,
Stop => Stopped
}
}
}
sm! {
Volume {
InitialStates { Muted }
Muted {
Unmute => Unmuted
}
Unmuted {
Mute => Muted,
VolumeUp => Unmuted,
VolumeDown => Unmuted
}
}
}
性能提示
sm
库在编译时生成所有状态转换代码,运行时没有动态查找或哈希表开销- 状态转换是纯函数式的,每次转换返回新状态机实例
- 状态数据通常很小(通常只是一个枚举),复制成本低
适用场景
- 游戏中的角色状态管理
- 网络协议实现
- UI界面状态控制
- 任何需要严格状态转换规则的业务逻辑