rust-rule-engine 0.13.4

A high-performance rule engine for Rust with RETE-UL algorithm (2-24x faster), CLIPS-inspired features (Template System, Defglobal, Deffacts, Test CE, Conflict Resolution), GRL support, and ~98% Drools compatibility
Documentation

Rust Rule Engine v0.13.4 ๐Ÿฆ€โšก

Crates.io Documentation License: MIT Build Status

A high-performance rule engine for Rust with RETE-UL algorithm, CLIPS-inspired features, Plugin System, and GRL (Grule Rule Language) support. Designed for production use with good Drools compatibility.

๐Ÿ”— GitHub | Documentation | Crates.io


โœจ What's New in v0.13.4

โšก Variable-to-Variable Comparison in RETE - Dynamic threshold comparisons!

  • ๐Ÿ”„ Compare Variables - Direct comparison between fact fields (e.g., Facts.L1 > Facts.L1Min)
  • ๐Ÿ“Š Dynamic Thresholds - No hardcoded values, change thresholds on-the-fly
  • ๐ŸŽฏ RETE-UL Support - Full integration with incremental engine
  • ๐Ÿ“ GRL Syntax - Natural syntax: when (Facts.value > Facts.threshold)
  • โšก Efficient Evaluation - Leverages RETE's pattern matching
  • ๐Ÿ”ง Flexible Rules - Same rule adapts to different threshold configurations
  • โœ… Production Ready - Battle-tested with complex eligibility rules

See Variable Comparison Demo โ†’ | Test Variable Comparison โ†’

Previous Updates

v0.13.0 (Earlier)

โšก Conflict Resolution Strategies - CLIPS/Drools-inspired rule ordering!

  • ๐ŸŽฏ 8 Strategies - Salience, LEX, MEA, Depth, Breadth, Simplicity, Complexity, Random
  • ๐Ÿ“Š Priority-Based - Control rule execution order with salience
  • ๐Ÿ• Recency-Based - Most recent facts fire first (LEX)
  • ๐Ÿ” Specificity - More specific rules fire first (Complexity, MEA)
  • โš™๏ธ Performance - Simple rules before complex (Simplicity)
  • ๐Ÿ”„ Dynamic Switching - Change strategies at runtime
  • โœ… CLIPS Compatible - Industry-standard conflict resolution
  • ๐Ÿ“ˆ ~98% Drools Parity - Enhanced compatibility

See Conflict Resolution Demo โ†’ | CLIPS Features Guide โ†’

Previous Updates

v0.12.0

๐Ÿงช Test CE (Conditional Element) - CLIPS-inspired arbitrary boolean expressions!

  • ๐Ÿ”ฌ Test CE Syntax - Call arbitrary functions in rule conditions without operators
  • ๐Ÿ“ GRL Support - Parse test(function(args)) directly from .grl files
  • ๐ŸŽฏ Native Engine - Fully implemented with function registry
  • โšก Truthy Evaluation - Automatic boolean conversion for all value types
  • ๐Ÿ”— Negation Support - Use !test() for negated conditions
  • ๐Ÿค Combined Conditions - Mix test() with regular conditions using AND/OR
  • ๐Ÿ“š Multiple Arguments - Support functions with any number of arguments

See Test CE Demo โ†’

v0.11.0

๐ŸŽฏ Deffacts System - Initial fact definitions (CLIPS feature)!

  • ๐Ÿ“ฆ Deffacts - Pre-defined fact sets for initial state
  • ๐Ÿ”„ Reset Support - Restore original facts with reset_with_deffacts()
  • ๐Ÿ“‹ Multiple Sets - Organize initial facts by category
  • โœ… Template Integration - Type-safe initial facts
  • ๐Ÿ—๏ธ Builder API - Fluent interface for defining deffacts

See Deffacts Demo โ†’

v0.10.2

๐Ÿ“ง Metadata Update - Corrected author email contact information

v0.10.1

๐Ÿš€ RETE Performance Optimization + Comprehensive Benchmarks!

  • โšก RETE Fixed - Eliminated infinite loop issue, now blazing fast
  • ๐Ÿ“Š Benchmarked - Comprehensive comparison: Traditional vs RETE
  • ๐Ÿ”ฅ 2-24x Faster - RETE shows 2x speedup at 10 rules, 24x at 50+ rules
  • โœ… Production Ready - Max iterations guard, optimized agenda management
  • ๐Ÿ“ˆ Scalability Proven - ~5ยตs per rule, scales linearly

See Benchmark Results โ†’

v0.10.0

  • ๐Ÿ”ง Function Calls in WHEN - Call AI/custom functions directly in rule conditions
  • ๐Ÿ“‹ Template System - Type-safe schema definitions for structured facts
  • ๐ŸŒ Defglobal - Global variables with thread-safe access
  • ๐Ÿ“ˆ Drools Compatibility - ~97% Drools parity

See Release Notes โ†’ | CLIPS Features Guide โ†’


๐Ÿš€ Key Features

Native Engine

  • GRL Support - Full Grule-compatible syntax
  • Function Calls in WHEN - Call functions directly in conditions (NEW in v0.10.0)
  • Plugin System - 44+ actions, 33+ functions
  • Knowledge Base - Centralized rule management
  • Type Safety - Rust's compile-time guarantees
  • Production Ready - REST API, monitoring, health checks

RETE-UL Engine (Recommended for 50+ rules)

  • ๐Ÿš€ High Performance - Efficient RETE algorithm with incremental updates
  • ๐Ÿ”ฅ RETE Algorithm - Advanced pattern matching with good Drools compatibility
  • ๐Ÿ”„ Variable Comparison - Compare fact fields dynamically (L1 > L1Min) (v0.13.0)
  • ๐Ÿ“‹ Template System - Type-safe structured facts (v0.10.0)
  • ๐ŸŒ Defglobal - Global variables across firings (v0.10.0)
  • ๐Ÿ“ฆ Deffacts - Initial fact definitions (v0.11.0)
  • ๐Ÿงช Test CE - Arbitrary boolean expressions in rules (v0.12.0)
  • โšก Conflict Resolution - 8 CLIPS strategies (Salience, LEX, MEA, etc.) (v0.13.0)
  • ๐ŸŽฏ Incremental Updates - Only re-evaluate affected rules
  • ๐Ÿง  Working Memory - FactHandles with insert/update/retract
  • ๐Ÿ”— Variable Binding - Cross-pattern $var syntax
  • ๐Ÿ’พ Memoization - Efficient caching for repeated evaluations

Choose Your Engine:

  • < 10 rules โ†’ Native Engine (simpler API, plugin support)
  • 10-50 rules โ†’ Either (RETE ~2x faster)
  • 50+ rules โ†’ RETE-UL Engine (2-24x faster, highly recommended)
  • Both needs โ†’ Hybrid approach

๐Ÿ“Š Performance at 50 rules: RETE shows good performance improvements over traditional engine!

๐Ÿ“– Engine Comparison Guide โ†’ | Quick Start Guide โ†’


๐Ÿ“ฆ Installation

[dependencies]
rust-rule-engine = "0.13.4"

Optional Features

# Enable streaming support
rust-rule-engine = { version = "0.13.4", features = ["streaming"] }

๐ŸŽฏ Quick Start

Option 1: Native Engine (Simple & Plugin-rich)

use rust_rule_engine::{RustRuleEngine, Facts, Value};

fn main() -> Result<(), Box<dyn std::error::Error>> {
    // Create engine with plugins
    let mut engine = RustRuleEngine::new();
    engine.load_default_plugins()?;

    // Load rules from GRL file
    engine.load_rules_from_file("rules/discount.grl")?;

    // Add facts
    let mut facts = Facts::new();
    facts.set("customer.tier", Value::String("gold".to_string()));
    facts.set("order.amount", Value::Float(1500.0));

    // Execute rules
    engine.execute(&mut facts)?;

    // Get result
    println!("Discount: {}", facts.get("order.discount"));

    Ok(())
}

GRL Rule Example (rules/discount.grl):

rule "GoldCustomerDiscount" salience 10 {
    when
        customer.tier == "gold" && order.amount > 1000
    then
        order.discount = order.amount * 0.15;
        Log("Applied 15% gold customer discount");
}

Option 2: RETE-UL Engine (High Performance)

use rust_rule_engine::rete::{
    IncrementalEngine, GrlReteLoader, TypedFacts, FactValue,
    TemplateBuilder, FieldType
};

fn main() -> Result<(), Box<dyn std::error::Error>> {
    let mut engine = IncrementalEngine::new();

    // Optional: Define template for type safety
    let order_template = TemplateBuilder::new("Order")
        .required_string("order_id")
        .float_field("amount")
        .float_field("discount")
        .build();
    engine.templates_mut().register(order_template);

    // Load rules from GRL
    GrlReteLoader::load_from_file("rules/discount.grl", &mut engine)?;

    // Insert facts with validation
    let mut order = TypedFacts::new();
    order.set("order_id", FactValue::String("ORD-001".to_string()));
    order.set("amount", FactValue::Float(1500.0));

    let handle = engine.insert_with_template("Order", order)?;

    // Fire rules
    engine.reset();
    let fired = engine.fire_all();
    println!("Fired {} rules", fired.len());

    // Query results
    if let Some(order) = engine.working_memory().get(&handle) {
        println!("Discount: {:?}", order.data.get("discount"));
    }

    Ok(())
}

๐Ÿ”„ NEW: Variable-to-Variable Comparison (v0.13.0)

The RETE-UL engine now supports comparing variables directly with each other!

This powerful feature enables dynamic threshold comparisons without hardcoding values in rules, making your rule logic more flexible and reusable.

โœจ Why Variable Comparison?

Traditional Approach (Hardcoded):

rule "CheckAge" {
    when customer.age > 18  // Hardcoded threshold
    then customer.eligible = true;
}

New Approach (Dynamic):

rule "CheckAge" {
    when customer.age > settings.minAge  // Dynamic threshold
    then customer.eligible = true;
}

๐Ÿ“– Real-World Example: Product Eligibility

Business Scenario: FamiCanxi product requires customers to meet dynamic thresholds for L1 and CM2 scores that can vary based on market conditions.

GRL Rule (famicanxi_rules.grl):

rule "FamiCanxi Product Eligibility Rule" salience 50 {
  when
    (Facts.L1 > Facts.L1Min) &&
    (Facts.CM2 > Facts.Cm2Min) &&
    (Facts.productCode == 1)
  then
    Facts.levelApprove = 1;
}

RETE-UL Implementation:

use rust_rule_engine::rete::{GrlReteLoader, IncrementalEngine, TypedFacts};

fn main() -> Result<(), Box<dyn std::error::Error>> {
    let mut engine = IncrementalEngine::new();

    // Load rule with variable comparisons
    GrlReteLoader::load_from_file("examples/famicanxi_rules.grl", &mut engine)?;

    // Insert facts with dynamic thresholds
    let mut facts = TypedFacts::new();
    facts.set("L1", 100i64);        // Customer score
    facts.set("L1Min", 50i64);      // Dynamic threshold (can change per request)
    facts.set("CM2", 80i64);        // Customer CM2 score
    facts.set("Cm2Min", 60i64);     // Dynamic threshold
    facts.set("productCode", 1i64);

    engine.insert("Facts".to_string(), facts);
    engine.reset();

    let fired = engine.fire_all();
    println!("Rules fired: {}", fired.len()); // Output: Rules fired: 1

    Ok(())
}

๐ŸŽฏ Key Benefits

  1. Dynamic Business Rules - Change thresholds without modifying rule code
  2. A/B Testing - Test different threshold configurations easily
  3. Multi-Tenant Support - Different thresholds per customer/region
  4. Configuration-Driven - Rules adapt to configuration changes
  5. Reduced Code Duplication - One rule handles multiple scenarios

๐Ÿ“Š Supported Comparisons

// Numeric comparisons
Facts.value > Facts.threshold
Facts.value >= Facts.minimum
Facts.value < Facts.maximum
Facts.value <= Facts.limit
Facts.value == Facts.target
Facts.value != Facts.excluded

// Mixed: variable with constant
Facts.value > Facts.threshold && Facts.status == "active"

// Multiple variable comparisons
(Facts.minValue < Facts.value) && (Facts.value < Facts.maxValue)

๐Ÿงช Test Examples

See complete working examples:


๐Ÿ”ง Function Calls in WHEN Clause

v0.10.0 introduces the ability to call functions directly in rule conditions!

โœจ Before (Rule Chaining)

rule "Step1: Call AI" {
    when Customer.needsCheck == true
    then set(Customer.sentiment, aiSentiment(Customer.feedback));
}

rule "Step2: Check Result" {
    when Customer.sentiment == "negative"
    then Alert("Negative feedback detected!");
}

โœจ After (Direct Function Calls)

rule "Check Sentiment" {
    when aiSentiment(Customer.feedback) == "negative"
    then Alert("Negative feedback detected!");
}

๐Ÿ“– Use Cases

AI/ML Integration:

rule "Fraud Detection" {
    when aiFraud(Transaction.amount, Transaction.userId) == true
    then set(Transaction.status, "blocked");
}

Business Logic:

rule "Credit Check" {
    when creditScore(Customer.id) > 750
    then set(Customer.tier, "premium");
}

Data Validation:

rule "Email Validation" {
    when validateEmail(User.email) == false
    then set(User.error, "Invalid email format");
}

See ai_functions_in_when.rs for complete examples!


๐Ÿ“š Documentation

๐Ÿ“– Getting Started

๐Ÿ”ง Core Features

๐Ÿš€ RETE-UL Engine

๐ŸŒ Distributed & Production

๐Ÿ“‹ Reference


๐Ÿ–ฅ๏ธ VS Code Extension

Install GRL Syntax Highlighting for .grl files:

Features:

  • Syntax highlighting for GRL
  • Snippets for rules, actions, functions
  • Auto-detection of .grl files

Install: Search grl-syntax-highlighting in VS Code Extensions


๐ŸŽฏ Use Cases

1. Business Rules Engine

// Pricing, discounts, loyalty programs
rule "VIPDiscount" {
    when customer.points > 1000
    then order.discount = 0.20;
}

2. Dynamic Eligibility & Thresholds (NEW!)

// Product eligibility with dynamic thresholds
rule "ProductEligibility" {
    when (customer.score > settings.minScore) &&
         (customer.income > settings.minIncome) &&
         (customer.age >= settings.minAge)
    then customer.eligible = true;
}

// Credit limit based on dynamic risk assessment
rule "CreditLimit" {
    when (customer.creditScore > risk.threshold) &&
         (customer.debtRatio < risk.maxDebtRatio)
    then customer.creditLimit = customer.income * risk.multiplier;
}

3. Fraud Detection

// Real-time fraud scoring
rule "HighRiskTransaction" {
    when transaction.amount > 10000 &&
         transaction.location != customer.usual_location
    then fraud.score = 0.85;
}

4. Workflow Automation

// Multi-step approval workflows
rule "ManagerApproval" agenda-group "approvals" {
    when request.amount > 5000
    then request.requires_manager = true;
}

5. Real-Time Systems

// IoT, monitoring, alerts
rule "TemperatureAlert" {
    when sensor.temp > 80
    then Alert.send("High temperature!");
}

More examples: examples/ directory


โšก Performance

RETE-UL Engine Benchmarks

  • Pattern Matching: ~4ยตs per fact insertion (1000 facts)
  • Incremental Updates: 2x speedup (only affected rules)
  • Memoization: 99.99% cache hit rate
  • Template Validation: 1-2ยตs per fact
  • Global Variables: 120ns read, 180ns write

Native Engine Benchmarks

  • Rule Execution: ~10ยตs per rule (simple conditions)
  • Plugin Actions: ~2-5ยตs per action call
  • Facts Access: O(1) HashMap lookups

Comparison: Performance Guide


Automated GRL Test Harness

This repository includes a lightweight, data-driven test harness used to exercise the GRL examples in examples/rules and verify they still parse and run against the engine.

Purpose:

  • Provide end-to-end coverage for .grl example files without requiring full production action implementations.
  • Detect regressions in the parser, engine, and example rules.

Where to find it:

  • tests/grl_harness_data.rs โ€” the primary data-driven harness. It reads tests/grl_cases.yml, constructs Facts, loads the .grl file(s), builds a KnowledgeBase, registers lightweight action handlers and functions, executes the engine, and performs simple assertions.
  • tests/grl_harness.rs โ€” smaller smoke tests used by the harness and examples.
  • tests/grl_cases.yml โ€” YAML-driven cases. Each case points at a .grl file and provides initial_facts and optional expect checks.

Why it uses minimal action handlers:

Many GRL samples call custom actions (e.g., apply_discount, sendAlert, setEcoMode, etc.). To exercise the rules end-to-end without requiring external systems, the harness registers small, no-op or fact-mutating action handlers. These handlers are only for testing and live in tests/grl_harness_data.rs.

How to run the harness (local development / CI):

# from repository root (zsh)
cargo test --tests -- --nocapture

What to look for:

  • The harness prints a per-case log (e.g., "=== Running case: fraud_detection ===") and a small set of logs generated by the registered handlers and functions.
  • Each case prints the number of rules fired. The harness currently performs lightweight assertions (e.g., rules fired, and simple fact field checks) โ€” see tests/grl_harness_data.rs for details.

How to add or update cases:

  1. Add a new case to tests/grl_cases.yml with fields: name, grl, initial_facts, and optional expect.
  2. If the .grl uses custom actions not yet covered, either:
    • Add a small test handler in tests/grl_harness_data.rs (follow the existing pattern), or
    • Add sufficient initial_facts so rules can be exercised without that action being mandatory.
  3. Run the harness and verify the new case behaves as expected.

Notes & next improvements:

  • The harness currently registers many minimal handlers to unblock rule execution; a future iteration should replace no-ops with tighter, case-specific assertions so the tests verify meaningful behavior instead of only successful execution.
  • There are some compiler warnings in the codebase (missing docs, unused-variable warnings). These do not block tests but can be cleaned up to keep CI logs tidy.

Questions or contributions: If you'd like, I can (a) strengthen per-case assertions, (b) consolidate test handlers into helpers, or (c) add a GitHub Actions workflow to run the harness in CI.


๐Ÿค Contributing

We welcome contributions! See CONTRIBUTING.md for guidelines.

Development Setup

# Clone repository
git clone https://github.com/KSD-CO/rust-rule-engine.git
cd rust-rule-engine

# Run tests
cargo test

# Run examples
cargo run --example rete_template_globals_demo

# Build documentation
cargo doc --open

๐Ÿ“„ License

This project is licensed under the MIT License - see LICENSE file.


๐Ÿ™ Acknowledgments

Inspired by:

  • Drools - JBoss Rule Engine
  • CLIPS - NASA C Language Integrated Production System
  • Grule - Go Rule Engine

Special Thanks:

  • Rust community for amazing tools and libraries
  • Contributors who helped improve the engine
  • Users providing valuable feedback

๐Ÿ“ž Support


๐Ÿ“ˆ Stats

GitHub stars GitHub forks Crates.io downloads


Made with โค๏ธ by Ton That Vu

โญ Star us on GitHub | ๐Ÿ“ฆ Download from Crates.io