Skip to content

LoganFlaherty/banish

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

125 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Banish

Crates.io Docs.rs License

Banish is a declarative DSL for building rule-based state machines in Rust. States evaluate their rules until reaching a fixed point or triggering a transition, reducing control flow boilerplate.

Why Banish?

  • Fixed-Point Looping: Unlike a standard function that executes top-to-bottom once, states loop automatically until no rules are triggered.
  • Zero Runtime Overhead: Banish is a procedural macro. It generates standard, optimized Rust code at compile time. There is no interpreter or virtual machine.
  • Mix Standard Rust: The body of every rule is just standard Rust code. You don't have to learn a whole new language, just a new structure.
  • Self-Documenting: Banish structures your code into named States and Rules. This lets your code be understandable to other developers (or yourself six months later) without too much additional commenting.

Features

  • @States: Group logic into distinct states (e.g., @init, @process, @report).
  • Rules?: Rules execute only when their condition is true (e.g., increment ? tick < 120).
  • Fallback Branches!?: Provide alternate logic when a rule's condition is false.
  • Fixed-Point Evaluation: When a rule executes, the state re-evaluates. Evaluation continues until no rules trigger.
  • Implicit & Explicit Transitions: States transition in declaration order by default. Use => @state for explicit jumps.
  • Full Rust Integration: Rules have access to outer-scope variables, functions, and external crates.

Example

use banish::banish;

fn main() {
   let mut ticks: i32 = 0;
   let mut loop_count: i32 = 0;
   banish! {
        @red
            announce ? {
               ticks = 0;
               println!("Red light");
            }

            timer ? ticks < 3 {
                ticks += 1;
            }

        @green
            announce ? {
               println!("Green light");
            }

            timer ? ticks < 6 {
               ticks += 1;
            }

        @yellow
            announce ? {
               println!("Yellow light");
            }

            timer ? ticks < 10 {
                ticks += 1;
            } !? {
                loop_count += 1;
                => @red;
            }

            end ? loop_count == 1 { return; }
    }
}

See more examples here: https://github.com/LoganFlaherty/banish/blob/main/docs/README.md

Install

Cargo

cargo add banish

TOML

[dependencies]
banish = "1.1.5"

Contributions

Contributions are welcome.

Before opening a PR, please start a discussion outlining your proposed changes. This helps ensure alignment on design decisions and prevents duplicated effort.

The test suite includes all documented examples. Please run the tests locally before submitting a PR.

If your changes introduce new behavior or address edge cases, include corresponding tests. Additional coverage for missing or unclear cases is appreciated.