rust-rule-engine 0.1.1

A high-performance rule engine for Rust with GRL (Grule Rule Language) support, file-based rules, custom functions, and method calls
Documentation

🦀 Rust Rule Engine - GRL Edition

A powerful, high-performance rule engine for Rust supporting GRL (Grule Rule Language) syntax with advanced features like method calls, custom functions, object interactions, and both file-based and inline rule management.

Crates.io Documentation License: MIT

🌟 Key Features

  • 🔥 GRL-Only Support: Pure Grule Rule Language syntax (no JSON)
  • 📄 Rule Files: External .grl files for organized rule management
  • 📝 Inline Rules: Define rules as strings directly in your code
  • 📞 Custom Functions: Register and call user-defined functions from rules
  • 🎯 Method Calls: Support for Object.method(args) and property access
  • 🧠 Knowledge Base: Centralized rule management with salience-based execution
  • 💾 Working Memory: Facts system for complex object interactions
  • ⚡ High Performance: Optimized execution engine with cycle detection
  • 🛡️ Type Safety: Rust's type system ensures runtime safety
  • 🏗️ Builder Pattern: Clean API with RuleEngineBuilder
  • 📈 Execution Statistics: Detailed performance metrics and debugging

🚀 Quick Start

Add to your Cargo.toml:

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

📄 File-Based Rules

Create a rule file rules/example.grl:

rule "AgeCheck" salience 10 {
    when
        User.Age >= 18 && User.Country == "US"
    then
        User.setIsAdult(true);
        User.setCategory("Adult");
        log("User qualified as adult");
}

rule "VIPUpgrade" salience 20 {
    when
        User.IsAdult == true && User.SpendingTotal > 1000.0
    then
        User.setIsVIP(true);
        log("User upgraded to VIP status");
}
use rust_rule_engine::{RuleEngineBuilder, Value, Facts};
use std::collections::HashMap;

fn main() -> Result<(), Box<dyn std::error::Error>> {
    // Create engine with rule file
    let mut engine = RuleEngineBuilder::new()
        .with_rule_file("rules/example.grl")?
        .build();

    // Register custom functions
    engine.register_function("User.setIsAdult", |args, _| {
        println!("Setting adult status: {}", args[0]);
        Ok(Value::Boolean(true))
    });

    engine.register_function("User.setCategory", |args, _| {
        println!("Setting category: {}", args[0]);
        Ok(Value::String(args[0].to_string()))
    });

    // Create facts
    let facts = Facts::new();
    let mut user = HashMap::new();
    user.insert("Age".to_string(), Value::Integer(25));
    user.insert("Country".to_string(), Value::String("US".to_string()));
    user.insert("SpendingTotal".to_string(), Value::Number(1500.0));

    facts.add_value("User", Value::Object(user))?;

    // Execute rules
    let result = engine.execute(&facts)?;
    println!("Rules fired: {}", result.rules_fired);

    Ok(())
}

📝 Inline String Rules

Define rules directly in your code:

use rust_rule_engine::{RuleEngineBuilder, Value, Facts};
use std::collections::HashMap;

fn main() -> Result<(), Box<dyn std::error::Error>> {
    let grl_rules = r#"
        rule "HighValueCustomer" salience 20 {
            when
                Customer.TotalSpent > 1000.0
            then
                sendWelcomeEmail(Customer.Email, "GOLD");
                log("Customer upgraded to GOLD tier");
        }

        rule "LoyaltyBonus" salience 15 {
            when
                Customer.OrderCount >= 10
            then
                applyLoyaltyBonus(Customer.Id, 50.0);
                log("Loyalty bonus applied");
        }
    "#;

    // Create engine with inline rules
    let mut engine = RuleEngineBuilder::new()
        .with_inline_grl(grl_rules)?
        .build();

    // Register custom functions
    engine.register_function("sendWelcomeEmail", |args, _| {
        println!("📧 Welcome email sent to {} for {} tier", args[0], args[1]);
        Ok(Value::Boolean(true))
    });

    engine.register_function("applyLoyaltyBonus", |args, _| {
        println!("💰 Loyalty bonus of {} applied to customer {}", args[1], args[0]);
        Ok(Value::Number(args[1].as_number().unwrap_or(0.0)))
    });

    // Create facts
    let facts = Facts::new();
    let mut customer = HashMap::new();
    customer.insert("TotalSpent".to_string(), Value::Number(1250.0));
    customer.insert("OrderCount".to_string(), Value::Integer(12));
    customer.insert("Email".to_string(), Value::String("john@example.com".to_string()));
    customer.insert("Id".to_string(), Value::String("CUST001".to_string()));

    facts.add_value("Customer", Value::Object(customer))?;

    // Execute rules
    let result = engine.execute(&facts)?;
    println!("Rules fired: {}", result.rules_fired);

    Ok(())
}

🎯 GRL Rule Language Features

Supported Syntax

rule "RuleName" salience 10 {
    when
        Object.Property > 100 &&
        Object.Status == "ACTIVE"
    then
        Object.setCategory("HIGH_VALUE");
        processTransaction(Object.Id, Object.Amount);
        log("Rule executed successfully");
}

Operators

  • Comparison: >, >=, <, <=, ==, !=
  • Logical: &&, ||
  • Value Types: Numbers, Strings (quoted), Booleans (true/false)

Actions

  • Method Calls: Object.method(args)
  • Function Calls: functionName(args)
  • Logging: log("message")

📚 Examples

🛒 E-commerce Rules

rule "VIPCustomer" salience 20 {
    when
        Customer.TotalSpent > 5000.0 && Customer.YearsActive >= 2
    then
        Customer.setTier("VIP");
        sendWelcomePackage(Customer.Email, "VIP");
        applyDiscount(Customer.Id, 15.0);
        log("Customer upgraded to VIP");
}

rule "LoyaltyReward" salience 15 {
    when
        Customer.OrderCount >= 50
    then
        addLoyaltyPoints(Customer.Id, 500);
        log("Loyalty reward applied");
}

🚗 Vehicle Monitoring

rule "SpeedLimit" salience 25 {
    when
        Vehicle.Speed > Vehicle.SpeedLimit
    then
        triggerAlert(Vehicle.Id, "SPEED_VIOLATION");
        logViolation(Vehicle.Driver, Vehicle.Speed);
        Vehicle.setStatus("FLAGGED");
}

rule "MaintenanceDue" salience 10 {
    when
        Vehicle.Mileage > Vehicle.NextMaintenance
    then
        scheduleService(Vehicle.Id, Vehicle.Mileage);
        notifyDriver(Vehicle.Driver, "Maintenance due");
}

⚡ Performance & Architecture

Benchmarks

Rule Execution Performance:
• Simple conditions: ~10-50 microseconds
• Complex multi-condition rules: ~100-500 microseconds  
• Custom function calls: ~50-200 microseconds
• File-based rule loading: ~1-5 milliseconds

Memory Usage:
• Rule storage: ~1KB per rule
• Facts storage: ~100-500 bytes per fact
• Engine overhead: ~10KB base memory

Key Design Decisions

  • GRL-Only: Removed JSON support for cleaner, focused API
  • Dual Sources: Support both file-based and inline rule definitions
  • Custom Functions: Extensible function registry for business logic
  • Builder Pattern: Fluent API for easy engine configuration
  • Type Safety: Leverages Rust's type system for runtime safety
  • Zero-Copy: Efficient string and memory management

🏗️ Development

Building from Source

git clone https://github.com/your-repo/rust-rule-engine.git
cd rust-rule-engine
cargo build --release

Running Examples

# File-based rules with custom functions
cargo run --example rule_file_functions_demo

# Inline rules demonstration  
cargo run --example inline_rules_demo

# Complete GRL feature showcase
cargo run --example grule_demo

# Custom function registry
cargo run --example custom_functions_demo

# Builder pattern usage
cargo run --example builder_test

Testing

# Run all tests
cargo test

# Run with output
cargo test -- --nocapture

# Run specific test
cargo test integration_tests

Publishing

# Check package
cargo check

# Run all tests
cargo test

# Build documentation
cargo doc --no-deps

# Publish dry run
cargo publish --dry-run

# Publish to crates.io
cargo publish

📋 API Reference

Core Types

// Main engine builder
RuleEngineBuilder::new()
    .with_rule_file("path/to/rules.grl")?
    .with_inline_grl("rule content")?
    .with_config(config)
    .build()

// Value types
Value::Integer(42)
Value::Number(3.14)
Value::String("text".to_string())
Value::Boolean(true)
Value::Object(HashMap<String, Value>)

// Facts management
let facts = Facts::new();
facts.add_value("Object", value)?;
facts.get("Object")?;

// Execution results
result.rules_fired       // Number of rules that executed
result.cycle_count       // Number of execution cycles
result.execution_time    // Duration of execution

Function Registration

engine.register_function("functionName", |args, facts| {
    // args: Vec<Value> - function arguments
    // facts: &Facts - current facts state
    // Return: Result<Value, RuleEngineError>
    
    let param1 = &args[0];
    let param2 = args[1].as_number().unwrap_or(0.0);
    
    // Your custom business logic here
    println!("Function called with: {:?}", args);
    
    Ok(Value::String("Success".to_string()))
});

🤝 Contributing

Contributions are welcome! Please feel free to submit a Pull Request.

Development Setup

  1. Fork the repository
  2. Create your feature branch: git checkout -b feature/amazing-feature
  3. Make your changes and add tests
  4. Ensure all tests pass: cargo test
  5. Commit your changes: git commit -m 'Add amazing feature'
  6. Push to the branch: git push origin feature/amazing-feature
  7. Open a Pull Request

Guidelines

  • Follow Rust naming conventions
  • Add tests for new features
  • Update documentation for API changes
  • Ensure examples work with changes

📄 License

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

🎯 Roadmap

  • Enhanced GRL Support: More operators and complex conditions
  • Rule Templates: Reusable rule patterns
  • Performance Optimizations: Rule compilation and caching
  • Debugging Tools: Rule execution tracing and profiling
  • Integration Examples: Database, HTTP APIs, message queues
  • Rule Validation: Static analysis and rule conflict detection

📞 Support


Built with ❤️ in Rust 🦀