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

这个代码定义了:

  1. 名为 circuit_breaker 的状态机
  2. 初始状态为 Closed
  3. 状态转换规则,例如:在 HalfOpen 状态收到 Successful 输入时转移到 Closed 状态
  4. 输出规则,例如:在 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!");
}

这个示例展示了:

  1. 电梯的三种状态:空闲(Idle)、上升(MovingUp)和下降(MovingDown)
  2. 状态转换触发条件:呼叫电梯(CallUp/CallDown)、到达楼层(ReachedFloor)
  3. 输出动作:到达中间楼层时播报楼层(AnnounceFloor)
  4. 完整的电梯运行流程模拟

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等技术来为不同状态实现不同的行为。

回到顶部