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); // 编译错误
}

这个示例展示了:

  1. 定义了一个电梯状态机,有Idle、Moving和EmergencyStop三种状态
  2. 定义了Call、Arrive和Emergency三种转换事件
  3. 展示了如何创建状态机实例并进行状态转换
  4. 演示了状态机如何防止无效的状态转换(最后一行注释掉的代码会引发编译错误)

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
        }
    }
}

性能提示

  1. sm库在编译时生成所有状态转换代码,运行时没有动态查找或哈希表开销
  2. 状态转换是纯函数式的,每次转换返回新状态机实例
  3. 状态数据通常很小(通常只是一个枚举),复制成本低

适用场景

  • 游戏中的角色状态管理
  • 网络协议实现
  • UI界面状态控制
  • 任何需要严格状态转换规则的业务逻辑
回到顶部