Expand description
ยงrule_kit
A blazing-fast, composable, and DSL-friendly rule engine kit for Rust.
Define your rules. Plug your context (mutable or immutable). Let the engine do the rest.
ยงโจ Features
- Minimal core: no assumptions, no boilerplate
- Pluggable rules: implement
Rule<T>for any context (mutable support) - DSL-friendly: support JSON/YAML/Struct-based rules
- Built for scale: evaluate hundreds of rules with ease
- Supports mutable context during rule application for stateful workflows
ยง๐ Quick Start
Define a context (e.g., a struct), implement Rule<T> with mutable apply, and plug it into RuleEngine:
use rule_kit::{Rule, RuleEngine};
use rule_kit::builder::RuleEngineBuilder;
use rule_kit::utils::PriorityOrder;
#[derive(Debug)]
struct Order {
pub total: f64,
pub discount: f64,
}
#[derive(Debug, Clone)]
enum OrderRule {
DiscountIfHighValue,
}
impl Rule<Order> for OrderRule {
type RuleError = ();
fn name(&self) -> &str {
match self {
OrderRule::DiscountIfHighValue => "DiscountIfHighValue",
}
}
fn priority(&self) -> u32 {
1
}
fn evaluate(&self, ctx: &Order) -> Result<bool, Self::RuleError> {
match self {
OrderRule::DiscountIfHighValue => Ok(ctx.total > 100.0),
}
}
/// Note: `apply` takes `&mut self` and `&mut ctx`, allowing rule and context mutation.
fn apply(&mut self, ctx: &mut Order) -> Result<(), Self::RuleError> {
match self {
OrderRule::DiscountIfHighValue => {
let discount = ctx.total * 0.10;
ctx.discount += discount;
Ok(())
}
}
}
fn before_apply(&self, ctx: &Order) {
println!("Checking order total: {}", ctx.total);
}
fn after_apply(&self, ctx: &Order) {
println!("Applied discount, new total discount: {}", ctx.discount);
}
}
// fn main() {
let mut order = Order {
total: 150.0,
discount: 0.0,
};
let rules = vec![OrderRule::DiscountIfHighValue];
// Using RuleEngine directly; pass mutable reference to context
let mut engine = RuleEngine::new(rules.clone(), None);
engine.evaluate_all(&mut order).unwrap();
println!("Discount after RuleEngine: {:.2}", order.discount);
// Using builder (with priority); also requires mutable context
let mut order2 = Order {
total: 150.0,
discount: 0.0,
};
let mut engine_built = RuleEngineBuilder::new()
.with_rules(rules)
.priority_asc()
.build();
engine_built.evaluate_all(&mut order2).unwrap();
println!("Discount after RuleEngineBuilder: {:.2}", order2.discount);
// }ยง๐ฆ Design Philosophy
rule_kit is designed to be:
- Composable โ add your own rule logic without modifying the engine
- Extensible โ supports rule metadata, DSL parsing, logging, etc.
- Performant โ built with scaling in mind (Rayon-friendly)
- Flexible โ supports mutable context in rules for stateful business logic
You implement the Rule<T> trait for your domain, where apply can mutate both the rule instance and the context, enabling advanced scenarios like workflow progression, state updates, or side effects.
ยง๐ License
Licensed under:
- Apache License, Version 2.0 LICENSE
ยง๐งโ๐ป Author
Created and maintained by Jerry Maheswara
Feel free to reach out for suggestions, issues, or improvements!
ยงโค๏ธ Built with Love in Rust
This project is built with โค๏ธ using Rust โ a systems programming language that is safe, fast, and concurrent. Rust is the perfect choice for building reliable and efficient applications.
ยง๐ Contributing
Pull requests, issues, and feedback are welcome!
If you find this crate useful, give it a โญ and share it with others in the Rust community.
Re-exportsยง
pub use traits::Rule;pub use engine::RuleEngine;pub use builder::RuleEngineBuilder;pub use utils::PriorityOrder;
Modulesยง
- builder
- Provides the builder pattern for constructing a
RuleEngineinstance with fluent configuration. - engine
- Core rule evaluation engine that runs rules based on context and priority.
- error
- Contains error types used throughout the rule engine, including
error::RuleErroranderror::RuleEngineError. - traits
- Defines the
Ruletrait and any related rule abstractions. - utils
- Utility enums or structs used across the crate, such as
PriorityOrder.