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)的实现和代码生成。它通过声明式宏和过程宏提供了高效的状态机定义方式,可以显著减少样板代码,提高开发效率。

主要特性

  1. 简洁的状态机定义语法
  2. 编译时状态转换验证
  3. 自动生成状态转换逻辑
  4. 支持异步状态机
  5. 可扩展的事件处理系统

安装方法

在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()
}

最佳实践

  1. 为每个状态和事件添加文档注释
  2. 使用#[derive(Debug)]方便调试
  3. 考虑为状态机实现Default trait
  4. 对复杂状态机进行模块化拆分

注意事项

  1. 状态转换是编译时验证的,确保所有转换都明确定义
  2. 避免在状态机定义中包含过多业务逻辑
  3. 对于大型状态机,考虑使用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

这个示例展示了:

  1. 状态机的基本定义语法
  2. 状态转换的基本使用
  3. 自定义状态行为方法
  4. 状态机的实际使用流程

你可以通过修改状态和事件的定义,以及添加更多的自定义方法来扩展这个状态机的功能。

回到顶部