datalogic-rs
A fast, production-ready Rust engine for JSONLogic.
Effortlessly evaluate complex rules and dynamic expressions with a powerful, memory-efficient, and developer-friendly toolkit.
datalogic-rs brings the power of JSONLogic to Rust, focusing on speed, safety, and ease of use. Whether you’re building feature flags, dynamic pricing, or complex validation, this engine is designed to be flexible and robust.
What’s New in v4? We’ve redesigned the API to be more ergonomic and developer-friendly. If you need maximum speed with arena allocation, v3 is still available and maintained. Choose v4 for a smoother experience, or stick with v3 for raw performance—both are supported.
Key Features
- Thread-Safe: Compile your logic once, then evaluate it anywhere—no locks, no fuss.
- Intuitive API: Works seamlessly with
serde_json::Value. - Fully Compliant: Passes the official JSONLogic test suite.
- Extensible: Add your own operators with a simple trait.
- Templating Support: Preserve object structures for dynamic output.
- Battle-Tested: Used in production, with thorough test coverage.
- Feature-Rich: Over 50 built-in operators, including datetime and regex.
- Async-Ready: Integrates smoothly with Tokio and async runtimes.
Getting Started
1. Basic Usage
use DataLogic;
use json;
let engine = new;
let logic = json!;
let compiled = engine.compile.unwrap;
let result = engine.evaluate_owned.unwrap;
assert_eq!;
2. Quick JSON Evaluation
use DataLogic;
use json;
let engine = new;
let result = engine.evaluate_json.unwrap;
assert_eq!;
3. Thread-Safe Evaluation
use DataLogic;
use json;
use Arc;
let engine = new;
let logic = json!;
let compiled = engine.compile.unwrap;
// Share across threads
let engine2 = clone;
let compiled2 = clone;
spawn;
Installation
Add this to your Cargo.toml:
[]
= "4.0"
# Or use v3 if you need arena-based allocation for maximum performance
# datalogic-rs = "3.0"
Examples
Conditional Logic
use DataLogic;
use json;
let engine = new;
let logic = json!;
let compiled = engine.compile.unwrap;
let result = engine.evaluate_owned.unwrap;
assert_eq!;
Array Operations
use DataLogic;
use json;
let engine = new;
let logic = json!;
let compiled = engine.compile.unwrap;
let result = engine.evaluate_owned.unwrap;
assert_eq!;
String Operations
use DataLogic;
use json;
let engine = new;
let logic = json!;
let compiled = engine.compile.unwrap;
let result = engine.evaluate_owned.unwrap;
assert_eq!;
Math Operations
use DataLogic;
use json;
let engine = new;
let logic = json!;
let compiled = engine.compile.unwrap;
let result = engine.evaluate_owned.unwrap;
assert_eq!;
Custom Operators
Extend the engine with your own logic. Important: Custom operators receive unevaluated arguments—you must call evaluator.evaluate() to evaluate them:
use ;
use ;
;
let mut engine = new;
engine.add_operator;
// Works with literals
let result = engine.evaluate_json.unwrap;
assert_eq!;
// Also works with variable references (because we evaluate the argument)
let logic = json!;
let compiled = engine.compile.unwrap;
let result = engine.evaluate_owned.unwrap;
assert_eq!;
For more examples including averaging, range checking, and string formatting operators, see examples/custom_operator.rs.
Configuration
Customize evaluation behavior to match your needs:
Basic Configuration
use ;
use json;
// Configure how non-numeric values are handled in arithmetic
let config = default
.with_nan_handling;
let engine = with_config;
// Non-numeric values are ignored instead of throwing errors
let logic = json!;
let compiled = engine.compile.unwrap;
let result = engine.evaluate_owned.unwrap;
assert_eq!; // "text" is ignored
Configuration Options
| Option | Description | Default |
|---|---|---|
| NaN Handling | How to handle non-numeric values in arithmetic | ThrowError |
| Division by Zero | How to handle division by zero | ReturnBounds |
| Truthy Evaluator | How to evaluate truthiness (JavaScript, Python, StrictBoolean, Custom) | JavaScript |
| Loose Equality Errors | Whether to throw errors for incompatible types in == |
true |
| Numeric Coercion | Rules for converting values to numbers | Permissive |
Custom Truthiness
use ;
use Arc;
// Only positive numbers are truthy
let custom_evaluator = new;
let config = default
.with_truthy_evaluator;
let engine = with_config;
Configuration Presets
// Safe arithmetic - ignores invalid values
let engine = with_config;
// Strict mode - throws more errors
let engine = with_config;
Combining Configuration with Structure Preservation
let config = default
.with_nan_handling;
let engine = with_config_and_structure;
Advanced Features
Nested Data Access
use DataLogic;
use json;
let engine = new;
let logic = json!;
let data = json!;
let compiled = engine.compile.unwrap;
let result = engine.evaluate_owned.unwrap;
assert_eq!;
Error Handling
The try and throw operators provide exception-like error handling:
use DataLogic;
use json;
let engine = new;
// Basic try/catch - returns fallback on error
let logic = json!;
let compiled = engine.compile.unwrap;
let result = engine.evaluate_owned.unwrap;
assert_eq!; // Division by zero caught, returns fallback
// Throw custom errors
let logic = json!;
// Access error details in catch block
let logic = json!;
let compiled = engine.compile.unwrap;
let result = engine.evaluate_owned.unwrap;
assert_eq!;
Structured Objects (Templating)
Enable preserve_structure mode to use JSONLogic as a templating engine. Unknown keys become output fields instead of being treated as operators:
use DataLogic;
use json;
let engine = with_preserve_structure;
// Template with mixed operators and literal fields
let template = json!;
let compiled = engine.compile.unwrap;
let data = json!;
let result = engine.evaluate_owned.unwrap;
// Result: {
// "user": { "name": "Alice", "email": "alice@example.com", "verified": true },
// "generatedAt": "2024-01-15T10:30:00Z"
// }
This is useful for:
- API response transformation
- Dynamic document generation
- Configuration templating
For more examples, see examples/structured_objects.rs.
Async Support
Works seamlessly with async runtimes:
use DataLogic;
use json;
use Arc;
async
Use Cases
Feature Flags
Dynamic Pricing
Fraud Detection
Supported Operators
Over 50 built-in operators, including:
| Category | Operators |
|---|---|
| Comparison | ==, ===, !=, !==, >, >=, <, <= |
| Logic | and, or, !, !! |
| Arithmetic | +, -, *, /, %, min, max, abs, ceil, floor |
| Control Flow | if, ?: (ternary), ?? (coalesce) |
| Arrays | map, filter, reduce, all, some, none, merge, in, length, slice, sort |
| Strings | cat, substr, starts_with, ends_with, upper, lower, trim, split |
| Data Access | var, val, exists, missing, missing_some |
| DateTime | datetime, timestamp, now, parse_date, format_date, date_diff |
| Type | type (returns type name as string) |
| Error Handling | throw, try |
| Special | preserve (for structured object preservation) |
| Custom | User-defined operators via Operator trait |
Architecture
- Compilation: Parses and optimizes logic for fast evaluation.
- Evaluation: Uses OpCode dispatch and context stack for speed.
- Thread-Safe: Share compiled logic with zero-copy via Arc.
-
Compilation Phase: JSON logic is parsed and compiled into a
CompiledLogicstructure with:- Static evaluation of constant expressions
- OpCode assignment for built-in operators
- Thread-safe Arc wrapping for sharing across threads
-
Evaluation Phase: The compiled logic is evaluated against data with:
- Direct OpCode dispatch (avoiding string lookups)
- Context stack for nested evaluations
- Zero-copy operations where possible
Performance Optimizations
- OpCode dispatch for built-in operators
- Static evaluation of constant expressions
- SmallVec for small arrays
- Arc sharing for thread safety
- Cow types for efficient value passing
About Plasmatic
Created by Plasmatic, building open-source tools for financial infrastructure and data processing.
Check out our other projects:
- DataFlow-rs: Event-driven workflow orchestration in Rust.
License
Licensed under Apache 2.0. See LICENSE for details.