Rust宏扩展库sm_macro的使用:高效代码生成与过程宏开发工具
Rust宏扩展库sm_macro的使用:高效代码生成与过程宏开发工具
特性
- 安全 - 通过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_macro的状态机示例,展示了如何定义状态、转换以及使用状态机:
extern crate sm;
use sm::sm;
// 定义电梯状态机
sm! {
Elevator {
InitialStates { Idle }
// 电梯操作
CallElevator {
Idle => MovingUp,
MovingUp => MovingUp, // 已在移动中
MovingDown => MovingUp // 改变方向
}
ReachFloor {
MovingUp => Idle,
MovingDown => Idle
}
EmergencyStop {
Idle, MovingUp, MovingDown => Emergency
}
Reset {
Emergency => Idle
}
}
}
fn main() {
use Elevator::*;
// 创建初始状态为Idle的电梯
let mut elevator = Machine::new(Idle);
// 呼叫电梯
elevator = elevator.transition(CallElevator);
assert_eq!(elevator.state(), MovingUp);
// 到达楼层
elevator = elevator.transition(ReachFloor);
assert_eq!(elevator.state(), Idle);
// 紧急停止
elevator = elevator.transition(EmergencyStop);
assert_eq!(elevator.state(), Emergency);
// 重置
elevator = elevator.transition(Reset);
assert_eq!(elevator.state(), Idle);
println!("Elevator state machine works as expected!");
}
完整示例demo
以下是基于sm_macro的交通灯状态机完整示例:
extern crate sm;
use sm::sm;
// 定义交通灯状态机
sm! {
TrafficLight {
InitialStates { Red }
// 状态转换
Change {
Red => Green,
Green => Yellow,
Yellow => Red
}
// 紧急情况
Emergency {
Red, Green, Yellow => BlinkingRed
}
// 恢复正常
Reset {
BlinkingRed => Red
}
}
}
fn main() {
use TrafficLight::*;
// 创建初始状态为Red的交通灯
let mut light = Machine::new(Red);
// 正常状态转换
light = light.transition(Change);
assert_eq!(light.state(), Green);
light = light.transition(Change);
assert_eq!(light.state(), Yellow);
light = light.transition(Change);
assert_eq!(light.state(), Red);
// 紧急情况处理
light = light.transition(Emergency);
assert_eq!(light.state(), BlinkingRed);
// 恢复正常运行
light = light.transition(Reset);
assert_eq!(light.state(), Red);
println!("Traffic light state machine works correctly!");
}
安装
在项目目录中运行以下Cargo命令:
cargo add sm_macro
或在Cargo.toml中添加以下行:
sm_macro = "0.9.0"
许可证
SM采用MIT或Apache-2.0双重许可证。
1 回复
Rust宏扩展库sm_macro的使用:高效代码生成与过程宏开发工具
介绍
sm_macro是一个Rust的过程宏库,旨在简化状态机(State Machine)的实现和代码生成。它通过声明式宏和过程宏提供了高效的状态机定义方式,可以显著减少样板代码,提高开发效率。
主要特性
- 简洁的状态机定义语法
- 编译时状态转换验证
- 自动生成状态转换逻辑
- 支持异步状态机
- 可扩展的事件处理系统
安装方法
在Cargo.toml中添加依赖:
[dependencies]
sm_macro = "0.3"
基本使用方法
1. 定义状态机
use sm_macro::sm;
sm! {
Lock {
States { Locked, Unlocked }
Events { TurnKey, Push }
Transitions {
Locked => TurnKey => Unlocked
Unlocked => TurnKey => Locked
Unlocked => Push => Locked
}
}
}
2. 使用生成的状态机
fn main() {
let mut lock = Lock::new();
assert_eq!(lock.state(), LockState::Locked);
lock.process_event(LockEvent::TurnKey);
assert_eq!(lock.state(), LockState::Unlocked);
lock.process_event(LockEvent::Push);
assert_eq!(lock.state(), LockState::Locked);
}
高级功能
自定义状态行为
sm! {
TrafficLight {
States { Red, Yellow, Green }
Events { Change }
Transitions {
Red => Change => Green
Green => Change => Yellow
Yellow => Change => Red
}
#[derive(Debug)]
impl TrafficLight {
pub fn color_duration(&self) -> u32 {
match self.state() {
TrafficLightState::Red => 30,
TrafficLightState::Yellow => 5,
TrafficLightState::Green => 25,
}
}
}
}
}
异步状态机
use sm_macro::sm;
use async_trait::async_trait;
sm! {
async AsyncMachine {
States { Start, Processing, Done }
Events { Begin, Complete }
Transitions {
Start => Begin => Processing
Processing => Complete => Done
}
#[async_trait]
impl AsyncMachine {
pub async fn process_data(&mut self) {
if let Processing = self.state() {
// 异步处理逻辑
tokio::time::sleep(std::time::Duration::from_secs(1).await;
self.process_event(AsyncMachineEvent::Complete).await;
}
}
}
}
}
过程宏开发
sm_macro也可以作为过程宏开发的工具库使用:
use proc_macro::TokenStream;
use sm_macro::StateMachineBuilder;
#[proc_macro]
pub fn define_state_machine(input: TokenStream) -> TokenStream {
StateMachineBuilder::from_input(input)
.build()
.unwrap_or_else(|err| err.to_compile_error())
.into()
}
最佳实践
- 为每个状态和事件添加文档注释
- 使用
#[derive(Debug)]
方便调试 - 考虑为状态机实现
Default
trait - 对复杂状态机进行模块化拆分
注意事项
- 状态转换是编译时验证的,确保所有转换都明确定义
- 避免在状态机定义中包含过多业务逻辑
- 对于大型状态机,考虑使用
sm_macro
的模块化功能
sm_macro通过简洁的DSL和强大的代码生成能力,可以显著简化Rust中状态机的实现,特别适合游戏开发、网络协议实现和复杂业务逻辑建模等场景。
完整示例demo
下面是一个完整的门锁状态机示例,展示了sm_macro的核心功能:
use sm_macro::sm;
// 定义门锁状态机
sm! {
/// 门锁状态机
DoorLock {
/// 可能的状态
States { Locked, Unlocked }
/// 可能的事件
Events { InsertKey, TurnKey, RemoveKey }
/// 状态转换规则
Transitions {
Locked => InsertKey => Locked
Locked => TurnKey => Unlocked
Unlocked => TurnKey => Locked
Unlocked => RemoveKey => Locked
}
#[derive(Debug)]
impl DoorLock {
/// 检查门锁是否安全
pub fn is_safe(&self) -> bool {
match self.state() {
DoorLockState::Locked => true,
DoorLockState::Unlocked => false,
}
}
}
}
}
fn main() {
// 创建新的门锁实例,初始状态为Locked
let mut door_lock = DoorLock::new();
println!("Initial state: {:?}", door_lock.state());
// 插入钥匙(状态不变)
door_lock.process_event(DoorLockEvent::InsertKey);
println!("After InsertKey: {:?}", door_lock.state());
// 转动钥匙解锁
door_lock.process_event(DoorLockEvent::TurnKey);
println!("After TurnKey: {:?}", door_lock.state());
println!("Is safe? {}", door_lock.is_safe());
// 移除钥匙(状态变为Locked)
door_lock.process_event(DoorLockEvent::RemoveKey);
println!("After RemoveKey: {:?}", door_lock.state());
// 再次转动钥匙解锁
door_lock.process_event(DoorLockEvent::TurnKey);
println!("After TurnKey: {:?}", door_lock.state());
}
示例输出:
Initial state: Locked
After InsertKey: Locked
After TurnKey: Unlocked
Is safe? false
After RemoveKey: Locked
After TurnKey: Unlocked
这个示例展示了:
- 状态机的基本定义语法
- 状态转换的基本使用
- 自定义状态行为方法
- 状态机的实际使用流程
你可以通过修改状态和事件的定义,以及添加更多的自定义方法来扩展这个状态机的功能。