#domain-specific-language #state-machine #dsl

fluent_state_machine

A domain-specific language (DSL) for creating state machines in Rust

5 releases (breaking)

0.5.0 Mar 11, 2024
0.4.0 Mar 11, 2024
0.3.0 Mar 11, 2024
0.2.0 Mar 5, 2024
0.1.0 Mar 5, 2024

#1303 in Algorithms

MIT license

12KB
142 lines

State Machine DSL

This is a Rust project that provides a domain-specific language (DSL) for creating state machines.

Getting Started

These instructions will get you a copy of the project up and running on your local machine for development and testing purposes.

Prerequisites

You need to have Rust and Cargo installed on your machine. If you don't have them installed, you can get them from here.

Cloning the Repository

To clone the repository, run the following command:

git clone https://github.com/hansaskov1/state_machine_dsl.git
cd state_machine_dsl

Running the Project

You can run one of the three available examples cd_player, turnstile_enum, turnstile_str. Here is how to run the cd_player example

cargo run --example cd_player

Running the Tests

You can run the tests with:

cargo test

Code Examples

Creating a Turnstile State Machine with String Literals

fn main() {
    let mut turnstyle = StateMachineBuilder::new((), "Locked")
        .state("Locked")
            .on("Coin").go_to("Unlocked")
        .state("Unlocked")
            .on("Push").go_to("Locked")
        .build().unwrap();

    turnstyle.trigger("Coin");
    println!("State: {}", turnstyle.state);
}

This code will print out State: UnLocked

Creating a Turnstile State Machine with Enums

#[derive(Debug, Clone, Copy, PartialEq)]
enum State {
    Locked,
    UnLocked
}

#[derive(PartialEq)]
enum Event {
    Coin,
    Push,
}

fn main() {
    
    let mut turnstyle = StateMachineBuilder::new((), State::Locked)
        .state(State::Locked)
            .on(Event::Coin).go_to(State::UnLocked)
        .state(State::UnLocked)
            .on(Event::Push).go_to(State::Locked)
        .build().unwrap();

    turnstyle.trigger(Event::Coin);
    println!("State: {:?}", turnstyle.state);
}

This will also print out "State: UnLocked"

And here is a more complex example for a Cd-Player

fn main() {

    // Create store for state machine. In this case it is an integer
    let track = 0;
    
    let mut cd_player = StateMachineBuilder::new( track, "Stopped")
        .state("Stopped")
            .on("Play").go_to("Playing").only_if(|track| *track > 0 )
            .on("Forward").update(|track| *track += 1 )
            .on("Backward").update(|track| *track -= 1)
        .state("Playing")
            .on("Stop").go_to("Stopped").then(|track| *track = 0)
            .on("Pause").go_to("Paused")
        .state("Paused")
            .on("Play").go_to("Playing")
            .on("Stop").go_to("Stopped").then(|track| *track = 0)
            .on("Forward").update(|track| *track += 1)
            .on("Backward").update(|track| *track -= 1)
        .build()
        .unwrap();

    println!("Track: {}, State: {}", cd_player.store, cd_player.state);

    cd_player.trigger("Forward");
    println!("Track: {}, State: {}", cd_player.store, cd_player.state);

    cd_player.trigger("Play");
    println!("Track: {}, State: {}", cd_player.store, cd_player.state);
}

Running this example gives us the following output: " Track: 0, State: Stopped Track: 1, State: Stopped Track: 1, State: Playing "

No runtime deps