Crate rusty_rules

Source
Expand description

§Rusty Rules

A blazingly fast, flexible, and extensible rules engine written in Rust. Evaluate complex logical rules against custom data structures using a simple JSON-based DSL.

§Features

  • Composable rules: Combine conditions with all, any, and not logical blocks for complex rule hierarchies
  • Custom fetchers: Extract values from data structures with named fetchers that accept arguments
  • Matcher support: String, regex, IP address, numeric, and boolean matchers out of the box
  • Custom operators: Define operators for advanced matching and domain-specific logic
  • Async support: Register async fetchers and operators for use with async/await contexts
  • JSON-schema validation: Validate rules with automatically generated JSON schema (requires validation feature)
  • Thread-safety option: Optional Send/Sync trait bounds with the send feature flag
  • Performance-focused: Designed for high-throughput rule evaluation with minimal overhead

§Basic Usage

Here’s how to use Rusty Rules with a custom context type:

use std::collections::HashMap;
use std::net::IpAddr;
use rusty_rules::{Engine, Value};
use serde_json::json;

// 1. Define context type
struct MyContext {
    method: String,
    path: String,
    headers: HashMap<String, String>,
    addr: IpAddr,
}

// 2. Create a new engine
let mut engine = Engine::new();

// 3. Register fetchers to extract values from context
engine.register_fetcher("method", |ctx: &MyContext, _args| {
    Ok(Value::from(&ctx.method))
});

engine.register_fetcher("header", |ctx: &MyContext, args| {
    Ok(args.first().and_then(|name| ctx.headers.get(name)).into())
});

engine.register_fetcher("addr", |ctx: &MyContext, _args| {
    Ok(Value::Ip(ctx.addr))
});

// 4. Compile a rule from JSON
let rule = engine.compile_rule(&json!({
    "all": [
        {"method": "GET"},
        {"header(host)": "www.example.com"},
        {"addr": {"ip": ["10.0.0.0/8"]}}
    ]
})).unwrap();

// 5. Evaluate the rule against a context
let ctx = MyContext {
    method: "GET".to_string(),
    path: "/api/v1/users".to_string(),
    headers: {
        let mut h = HashMap::new();
        h.insert("host".to_string(), "www.example.com".to_string());
        h
    },
    addr: "10.1.2.3".parse().unwrap(),
};

assert!(rule.evaluate(&ctx).unwrap());

§Rule Composition

Rules can be composed using logical operators:

{
    "all": [              // All conditions must match (logical AND)
        { "method": "GET" },
        { "path": { "regex": "^/api/v\\d+" } },
        {
            "any": [      // Any condition must match (logical OR)
                { "header(auth)": { "exists": true } },
                { "ip": { "cidr": "10.0.0.0/8" } }
            ]
        },
        {
            "not": [      // Negate the condition (logical NOT)
                { "header(user-agent)": "BadBot/1.0" }
            ]
        }
    ]
}

§Custom Operators

You can extend the engine with custom operators:

// Register a custom string prefix operator
engine.register_operator("starts_with", |value: JsonValue| {
    let prefix = value.as_str().ok_or("prefix must be a string")?.to_string();
    Ok(Operator::new(move |_, value| {
        Ok(value.as_str()
            .map(|s| s.starts_with(&prefix))
            .unwrap_or_default())
    }))
});

// Use the custom operator in a rule
let rule = engine.compile_rule(&json!({
    "path": {
        "starts_with": "/api/v1"
    }
})).unwrap();

§JSON Schema Validation

With the validation feature enabled, you can validate rules against a dynamically generated schema:

let rule = json!({
    "all": [
        {"method": "GET"},
        {"path": {
            "re": "^/api/v\\d+"
        }}
    ]
});

// Validate the rule against the engine's schema
let result = engine.validate_rule(&rule);

§Feature Flags

  • send - Enables Send and Sync trait bounds on all public types, making them safe to use across thread boundaries
  • validation - Enables JSON schema generation and validation functionality (adds jsonschema dependency)

Structs§

BoolMatcher
A matcher for boolean values.
DefaultMatcher
A flexible matcher without strict types.
Engine
Rules engine for registering fetchers/operators and parsing rules.
Fetcher
Holds a fetcher’s required matcher type and function.
IpMatcher
A matcher for IP subnets.
NumberMatcher
A matcher for number values.
RegexMatcher
A matcher for string values with regular expressions by default.
StringMatcher
A matcher for string values.
ValidationErrorvalidation
An error that can occur during validation.

Enums§

Error
Represents possible errors that can occur during rules parsing.
Operator
Represents an operator that used to check if a fetched value satisfies the condition.
Rule
Represents a rule, which can be a condition or a logical combination of other rules.
Value
Represents possible values returned by fetchers

Traits§

Matcher
Trait for types matchers
ToOperator

Type Aliases§

AsyncCheckFn
Callback type for async operator check function
AsyncFetcherFn
Callback type for async fetchers
CheckFn
Callback type for operator check function
FetcherFn
Callback type for fetchers