Skip to main content

fuel_limits/
fuel_limits.rs

1//! Fuel metering — in-loop counting and short-circuit behaviour.
2//!
3//! Run with: cargo run --example fuel_limits
4
5use fsm_guards::{evaluate, EvalCtx, GuardError};
6use serde_json::json;
7
8fn main() {
9    // ── short-circuit: or stops on first true ──────────────────────────────
10    // Build a 200-node branch that would blow a pre-walk budget.
11    let mut deep = json!({"==": [1, 2]});
12    for _ in 0..50 {
13        deep = json!({"and": [deep, {"==": [1, 2]}]});
14    }
15    let rule = json!({"or": [true, deep]});
16
17    let ctx = EvalCtx::new().with_fuel(5);
18    let result = evaluate(&rule, &json!({}), &ctx).unwrap();
19    println!("short-circuit or: {result}"); // true — only ~2 nodes visited
20
21    // ── budget exhausted ───────────────────────────────────────────────────
22    let rule = json!({"and": [
23        {"==": [1, 1]},
24        {"==": [2, 2]},
25        {"==": [3, 3]}
26    ]});
27
28    match evaluate(&rule, &json!({}), &EvalCtx::new().with_fuel(5)) {
29        Ok(v) => println!("passed with fuel:5 → {v}"),
30        Err(GuardError::FuelExceeded { limit }) => println!("exceeded limit:{limit}"),
31        Err(e) => println!("error: {e}"),
32    }
33
34    // ── default fuel (200) handles realistic guards comfortably ───────────
35    let ctx = EvalCtx::new(); // fuel: 200
36    let rule = json!({"and": [
37        {"==": [{"var": "status"}, "active"]},
38        {">=": [{"var": "score"}, 80]},
39        {"in": [{"var": "role"}, ["admin", "operator"]]}
40    ]});
41    let data = json!({"status": "active", "score": 95, "role": "admin"});
42    println!("realistic guard: {}", evaluate(&rule, &data, &ctx).unwrap()); // true
43}