# 🦀 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.
[](https://crates.io/crates/rust-rule-engine)
[](https://docs.rs/rust-rule-engine)
[](https://opensource.org/licenses/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`:
```toml
[dependencies]
rust-rule-engine = "0.1.0"
```
### 📄 File-Based Rules
Create a rule file `rules/example.grl`:
```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");
}
```
```rust
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:
```rust
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
```grl
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
```grl
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
```grl
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
```text
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
```bash
git clone https://github.com/your-repo/rust-rule-engine.git
cd rust-rule-engine
cargo build --release
```
### Running Examples
```bash
# 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
```bash
# Run all tests
cargo test
# Run with output
cargo test -- --nocapture
# Run specific test
cargo test integration_tests
```
### Publishing
```bash
# 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
```rust
// 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
```rust
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](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
- 📚 **Documentation**: [docs.rs/rust-rule-engine](https://docs.rs/rust-rule-engine)
- 🐛 **Issues**: [GitHub Issues](https://github.com/your-repo/rust-rule-engine/issues)
- 💬 **Discussions**: [GitHub Discussions](https://github.com/your-repo/rust-rule-engine/discussions)
---
**Built with ❤️ in Rust** 🦀