MCPcopy Index your code
hub / github.com/GoPlasmatic/datalogic-rs

github.com/GoPlasmatic/datalogic-rs @v5.0.0

Chat with this repo
repository ↗ · DeepWiki ↗ · release v5.0.0 ↗ · + Follow
1,759 symbols 5,567 edges 384 files 402 documented · 23%
What it actually does AI analysis from the code graph — generated when you open this
loading…
README

Plasmatic Logo

datalogic-rs

A fast, production-ready engine for JSONLogic — Rust core, Node-native, WASM, Python, Go, React debugger.

License: Apache 2.0 Rust Crates.io Documentation npm (node) npm (wasm) PyPI


What is datalogic-rs?

datalogic-rs is a fast Rust engine for JSONLogic, a JSON-shaped language for evaluating logical rules against data. Use it as a rule engine for business logic, a JSON template engine for response shaping, or a safe expression evaluator for user-supplied formulas — and run the same rules in Rust, Node.js (native via napi), the browser (WebAssembly), Python, Go, or a React visual debugger.

JSONLogic Online Debugger Demo

Try it live in the online playground — no install required.

Pick your package

The Rust crate is the engine. Every other package wraps it for a specific runtime — same rules, same semantics, same operators. Click through to the binding's own README for install, quick start, and the full API reference for that language.

Your stack Package Install Deep-dive
Rust application or service datalogic-rs cargo add datalogic-rs crates/datalogic-rs/README.md
Node.js service (TypeScript or JS) @goplasmatic/datalogic-node npm i @goplasmatic/datalogic-node bindings/node/README.md
Browser, Deno, Bun, Cloudflare Workers, edge runtimes @goplasmatic/datalogic-wasm (WebAssembly) npm i @goplasmatic/datalogic-wasm bindings/wasm/README.md
Python service or data pipeline datalogic-py pip install datalogic-py bindings/python/README.md
Go service datalogic-go go get github.com/GoPlasmatic/datalogic-rs/bindings/go/v5 bindings/go/README.md
Java / JVM service io.github.goplasmatic:datalogic Maven Central dependency bindings/jvm/README.md
.NET service Goplasmatic.Datalogic dotnet add package Goplasmatic.Datalogic bindings/dotnet/README.md
PHP service goplasmatic/datalogic composer require goplasmatic/datalogic bindings/php/README.md
React visual rule editor / debugger @goplasmatic/datalogic-ui npm i @goplasmatic/datalogic-ui ui/README.md
C ABI for new language bindings datalogic-c (in-tree) build locally — shared FFI surface for Go/JVM/.NET/PHP bindings/c/README.md

Not sure which one? If you're writing the rules and evaluating them in the same service, pick the binding for that service's language.

On Node.js, reach for @goplasmatic/datalogic-node — it's the native build (per-platform .node prebuild via napi-rs), which is materially faster than the WASM path. The WASM package is the right pick when you need a single artifact across browser + edge runtimes (Deno, Bun, Cloudflare Workers) or when you'd rather avoid per-platform prebuilt binaries.

If you're building a UI that lets humans author rules, also pull in @goplasmatic/datalogic-ui — it consumes the WASM binding and gives you a visual editor and step-through debugger.

Documentation

The full documentation site is the long-form home for everything below: the operator reference (all 59 built-ins, organised by category), advanced topics (templating, custom operators, tracing, configuration), and an interactive playground for trying rules live without installing anything. The rest of this README is the short version.

Three things you can build with it

1. Business rules

Encode access control, feature flags, and validation as JSON. Rules are data — store them in a database, send them over an API, change them without redeploys.

let result = datalogic_rs::eval_str(
    r#"{"and": [{">=": [{"var": "age"}, 18]}, {"==": [{"var": "status"}, "active"]}]}"#,
    r#"{"age": 25, "status": "active"}"#,
).unwrap();
assert_eq!(result, "true");

2. JSON templates

Shape one JSON payload into another. With templating mode, object keys flow through to the output and operator values become computed fields — the template's structure mirrors the response you want.

// Cargo.toml: datalogic-rs = { version = "5", features = ["templating"] }
use datalogic_rs::Engine;

let engine = Engine::builder().with_templating(true).build();
let result = engine.eval_str(
    r#"{"greeting": {"cat": ["Hello ", {"var": "name"}]},
        "isAdult": {">=": [{"var": "age"}, 18]}}"#,
    r#"{"name": "Jane", "age": 25}"#,
).unwrap();
// {"greeting":"Hello Jane","isAdult":true}

3. Expression evaluation

Let users author formulas; evaluate them safely without eval(). Arithmetic, comparisons, and array reductions are all built in.

let result = datalogic_rs::eval_str(
    r#"{"+": [{"var": "subtotal"}, {"var": "tax"}, {"var": "shipping"}]}"#,
    r#"{"subtotal": 100, "tax": 8.5, "shipping": 5}"#,
).unwrap();
assert_eq!(result, "113.5");

reduce, map, filter, and sort extend the same pattern to aggregations over arrays.

One rule, every runtime

The same JSONLogic rule runs unchanged across every supported runtime. Author the rule once; evaluate it on the server, in the browser, or inside a visual editor.

Rust — server-side, native:

let result = datalogic_rs::eval_str(
    r#"{">": [{"var": "x"}, 10]}"#,
    r#"{"x": 42}"#,
).unwrap();
// "true"

Node.js (native) — services, scripts, CLIs:

import { apply } from '@goplasmatic/datalogic-node';

const result = apply({ '>': [{ var: 'x' }, 10] }, { x: 42 });
// true

Browser / Deno / Bun / Cloudflare Workers — via WebAssembly:

import init, { evaluate } from '@goplasmatic/datalogic-wasm';

await init();
const result = evaluate('{">": [{"var": "x"}, 10]}', '{"x": 42}', false);
// "true"

Python — services, scripts, data pipelines:

from datalogic_py import apply

result = apply({">": [{"var": "x"}, 10]}, {"x": 42})
# True

Go — services, CLIs:

import datalogic "github.com/GoPlasmatic/datalogic-rs/bindings/go/v5"

out, _ := datalogic.Apply(`{">": [{"var": "x"}, 10]}`, `{"x": 42}`)
// "true"

React — drop-in visual debugger / editor:

import { DataLogicEditor } from '@goplasmatic/datalogic-ui';

<DataLogicEditor
  value={{ ">": [{ "var": "x" }, 10] }}
  data={{ x: 42 }}
/>

See the rule run live in your browser at the online playground.

Choosing your API: five tiers, one engine

Every binding exposes the same conceptual ladder — pick the entry point that matches how often you evaluate and how much control you want over allocation.

What it is Use when
Tier 0 — Module-level one-shoteval_str, eval, eval_into, compile Quick scripts, ad-hoc evaluation, no custom configuration
Tier 1 — Engine one-shotEngine::eval* You need custom operators, non-default config, or templating mode
Tier 2 — Session (hot loop)Engine::session() + Session::eval* You're evaluating compiled rules many times — services, batch jobs, request handlers
Tier 3 — Zero-copy evaluateEngine::evaluate(&Logic, data, &Bump) You want results that borrow directly into a caller-owned arena (specialised use)
Tier 4 — Traced evaluationEngine::trace() Debugging, visualising execution, building inspector UIs

Most callers want Tier 0 or Tier 2. Tier 0 is the right default for trying something out; reach for Tier 2 once the same rule is being evaluated repeatedly. Bindings expose the same ladder under language-idiomatic names — see each binding's README for the exact call sites. For the Rust deep-dive, including code per tier and runnable examples, see crates/datalogic-rs/README.md.

Highlights

  • Cross-platform — same engine, same rules in Rust, Node.js (native), browsers + edge runtimes (WASM), Python, Go, and a React UI
  • 59 built-in operators with full JSONLogic spec compliance — 57 in the default build plus 2 opt-in OpenFeature flagd-compatible operators (fractional, sem_ver) behind features = ["flagd"]
  • Compile once, evaluate millions of timesLogic is Send + Sync; share via Arc
  • Zero unsafe — built with #![forbid(unsafe_code)]
  • Arena-allocated evaluationbumpalo-backed; read-through ops borrow zero-copy from the input
  • serde_json is optional — opt in only when you need the value boundary
  • Configurable — NaN handling, division-by-zero, truthiness modes, numeric coercion
  • Custom operators via a simple trait — same idea exposed in every binding
  • Visual debugger + execution tracing for diagnosing rules

Performance

datalogic-rs is built for repeated evaluation. Compiled rules dispatch through a single OpCode enum (no string lookups), values live in a bumpalo::Bump arena (no per-result heap allocation), and read-through operators like var borrow zero-copy from the caller's input.

Geomeans across 44 suites (Apple M2 Pro, macOS 26.3, Rust 1.93, Node 24; median of 3 samples per cell, ~200 ms wall budget — see [tools/benchmark/BENCHMARK.md][bench] for the per-suite matrix, methodology, and caveats):

Library Config / setup Geomean ns/op vs dlrs:engine
datalogic-rs (native Rust, this repo) precompiled — dlrs:engine 9.7
json-logic-engine (TotalTechGeek, JS) compiled — json-logic-engine:compiled 47.2 4.9×
json-logic-engine (TotalTechGeek, JS) interpreted — json-logic-engine 160.3 16.5×
jsonlogic-rs (bestowinc, native Rust) default — jsonlogic-rs 218.0 22.5×
json-logic-js (jwadhams reference, JS) default — json-logic-js 423.5 43.7×
@goplasmatic/datalogic-wasm (WebAssembly, run in Node) compiled — dlrs:wasm:compiled 855.6 88.2×

The WASM row above measures the WebAssembly build

Extension points exported contracts — how you extend this code

EvalInput (Interface)
Adapter trait that converts a value into a `&'a DataValue<'a>` borrowed from the caller-supplied arena. **Sealed** — the [6 …
crates/datalogic-rs/src/eval_input.rs
CustomOperator (Interface)
Functional interface for a user-defined JSONLogic operator. The argument JSON is the pre-evaluated arguments as a JSON-a [4 …
bindings/jvm/src/main/java/com/goplasmatic/datalogic/CustomOperator.java
Subject (Interface)
(no doc) [3 implementers]
tools/benchmark/src/bin/compare.rs
OperatorFunc (FuncType)
OperatorFunc is the contract for a custom operator. argsJSON is a JSON-array string of pre-evaluated arguments (e.g. `"[
bindings/go/operator.go
TooltipProps (Interface)
(no doc)
ui/src/components/Tooltip.tsx
CustomOperator (Interface)
Custom operator hook for the [`Engine`]. Implementations receive args **already evaluated** as borrowed [`DataValue`] r [13 …
crates/datalogic-rs/src/lib.rs
DatalogicNative (Interface)
JNA library proxy for libdatalogic_c. Loaded lazily on first use. [1 implementers]
bindings/jvm/src/main/java/com/goplasmatic/datalogic/internal/DatalogicNative.java
Position (Interface)
(no doc)
ui/src/components/Tooltip.tsx

Core symbols most depended-on inside this repo

push
called by 303
crates/datalogic-rs/src/arena/context/mod.rs
len
called by 186
crates/datalogic-rs/src/operators/array/helpers.rs
is_empty
called by 124
crates/datalogic-rs/src/operators/array/helpers.rs
dispatch_node
called by 108
crates/datalogic-rs/src/engine/mod.rs
get
called by 92
crates/datalogic-rs/src/operators/array/helpers.rs
eval_str
called by 59
crates/datalogic-rs/src/trace.rs
compile
called by 58
crates/datalogic-rs/src/engine/mod.rs
build
called by 53
crates/datalogic-rs/src/builder.rs

Shape

Function 969
Method 497
Interface 142
Class 121
Enum 23
Struct 6
FuncType 1

Languages

Rust55%
TypeScript24%
Java6%
C#5%
PHP4%
Python3%

Modules by API surface

crates/datalogic-rs/src/arena/context/mod.rs42 symbols
crates/datalogic-rs/src/error/mod.rs35 symbols
crates/datalogic-rs/src/trace.rs33 symbols
crates/datalogic-rs/tests/error_serialization.rs32 symbols
bindings/jvm/src/main/java/com/goplasmatic/datalogic/internal/DatalogicNative.java31 symbols
bindings/dotnet/src/Datalogic/Native/NativeMethods.cs29 symbols
crates/datalogic-rs/src/engine/mod.rs27 symbols
crates/datalogic-rs/tests/config_test.rs23 symbols
crates/datalogic-rs/src/operators/array/helpers.rs23 symbols
tools/benchmark/src/lib.rs22 symbols
crates/datalogic-rs/tests/trace_test.rs21 symbols
crates/datalogic-rs/src/config.rs21 symbols

For agents

$ claude mcp add datalogic-rs \
  -- python -m otcore.mcp_server <graph>

⬇ download graph artifact