pub struct DataLogic { /* private fields */ }Expand description
The main DataLogic engine for compiling and evaluating JSONLogic expressions.
The engine provides a two-phase approach to logic evaluation:
- Compilation: Parse JSON logic into optimized
CompiledLogic - Evaluation: Execute compiled logic against data
§Features
- Thread-safe: Compiled logic can be shared across threads with
Arc - Extensible: Add custom operators via
add_operator - Structure preservation: Optionally preserve object structure for templating
- OpCode dispatch: Built-in operators use fast enum-based dispatch
§Example
use datalogic_rs::DataLogic;
use serde_json::json;
let engine = DataLogic::new();
let logic = json!({">": [{"var": "age"}, 18]});
let compiled = engine.compile(&logic).unwrap();
let data = json!({"age": 21});
let result = engine.evaluate_owned(&compiled, data).unwrap();
assert_eq!(result, json!(true));Implementations§
Source§impl DataLogic
impl DataLogic
Sourcepub fn new() -> Self
pub fn new() -> Self
Creates a new DataLogic engine with all built-in operators.
The engine includes 50+ built-in operators optimized with OpCode dispatch. Structure preservation is disabled by default.
§Example
use datalogic_rs::DataLogic;
let engine = DataLogic::new();Sourcepub fn with_preserve_structure() -> Self
pub fn with_preserve_structure() -> Self
Creates a new DataLogic engine with structure preservation enabled.
When enabled, objects with unknown operators are preserved as structured
templates, allowing for dynamic object generation. Custom operators
registered via add_operator are recognized and evaluated properly,
even within structured objects.
§Example
use datalogic_rs::DataLogic;
use serde_json::json;
let engine = DataLogic::with_preserve_structure();
let logic = json!({
"name": {"var": "user.name"},
"score": {"+": [{"var": "base"}, {"var": "bonus"}]}
});
// Returns: {"name": "Alice", "score": 95}§Custom Operators with Preserve Structure
Custom operators work seamlessly in preserve_structure mode:
use datalogic_rs::{DataLogic, Operator, ContextStack, Evaluator, Result, Error};
use serde_json::{json, Value};
use std::sync::Arc;
struct UpperOperator;
impl Operator for UpperOperator {
fn evaluate(&self, args: &[Value], context: &mut ContextStack,
evaluator: &dyn Evaluator) -> Result<Value> {
let val = evaluator.evaluate(&args[0], context)?;
Ok(json!(val.as_str().unwrap_or("").to_uppercase()))
}
}
let mut engine = DataLogic::with_preserve_structure();
engine.add_operator("upper".to_string(), Box::new(UpperOperator));
let logic = json!({
"message": {"upper": {"var": "text"}},
"count": {"var": "num"}
});
let compiled = engine.compile(&logic).unwrap();
let result = engine.evaluate(&compiled, Arc::new(json!({"text": "hello", "num": 5}))).unwrap();
// Returns: {"message": "HELLO", "count": 5}Sourcepub fn with_config(config: EvaluationConfig) -> Self
pub fn with_config(config: EvaluationConfig) -> Self
Creates a new DataLogic engine with a custom configuration.
§Arguments
config- The evaluation configuration
§Example
use datalogic_rs::{DataLogic, EvaluationConfig, NanHandling};
let config = EvaluationConfig::default()
.with_nan_handling(NanHandling::IgnoreValue);
let engine = DataLogic::with_config(config);Sourcepub fn with_config_and_structure(
config: EvaluationConfig,
preserve_structure: bool,
) -> Self
pub fn with_config_and_structure( config: EvaluationConfig, preserve_structure: bool, ) -> Self
Creates a new DataLogic engine with both configuration and structure preservation.
§Arguments
config- The evaluation configurationpreserve_structure- Whether to preserve object structure
§Example
use datalogic_rs::{DataLogic, EvaluationConfig, NanHandling};
let config = EvaluationConfig::default()
.with_nan_handling(NanHandling::IgnoreValue);
let engine = DataLogic::with_config_and_structure(config, true);Sourcepub fn config(&self) -> &EvaluationConfig
pub fn config(&self) -> &EvaluationConfig
Gets a reference to the current evaluation configuration.
Sourcepub fn preserve_structure(&self) -> bool
pub fn preserve_structure(&self) -> bool
Returns whether structure preservation is enabled.
Sourcepub fn add_operator(&mut self, name: String, operator: Box<dyn Operator>)
pub fn add_operator(&mut self, name: String, operator: Box<dyn Operator>)
Registers a custom operator with the engine.
Custom operators extend the engine’s functionality with domain-specific logic. They override built-in operators if the same name is used.
§Arguments
name- The operator name (e.g., “custom_calc”)operator- The operator implementation
§Example
use datalogic_rs::{DataLogic, Operator, ContextStack, Evaluator, Result, Error};
use serde_json::{json, Value};
struct DoubleOperator;
impl Operator for DoubleOperator {
fn evaluate(
&self,
args: &[Value],
_context: &mut ContextStack,
_evaluator: &dyn Evaluator,
) -> Result<Value> {
if let Some(n) = args.first().and_then(|v| v.as_f64()) {
Ok(json!(n * 2.0))
} else {
Err(Error::InvalidArguments("Argument must be a number".to_string()))
}
}
}
let mut engine = DataLogic::new();
engine.add_operator("double".to_string(), Box::new(DoubleOperator));Sourcepub fn has_custom_operator(&self, name: &str) -> bool
pub fn has_custom_operator(&self, name: &str) -> bool
Sourcepub fn compile(&self, logic: &Value) -> Result<Arc<CompiledLogic>>
pub fn compile(&self, logic: &Value) -> Result<Arc<CompiledLogic>>
Compiles a JSON logic expression into an optimized form.
Compilation performs:
- Static evaluation of constant expressions
- OpCode assignment for built-in operators
- Structure analysis for templating
The returned Arc<CompiledLogic> can be safely shared across threads.
§Arguments
logic- The JSON logic expression to compile
§Returns
An Arc-wrapped compiled logic structure, or an error if compilation fails.
§Example
use datalogic_rs::DataLogic;
use serde_json::json;
use std::sync::Arc;
let engine = DataLogic::new();
let logic = json!({"==": [1, 1]});
let compiled: Arc<_> = engine.compile(&logic).unwrap();Sourcepub fn evaluate(
&self,
compiled: &CompiledLogic,
data: Arc<Value>,
) -> Result<Value>
pub fn evaluate( &self, compiled: &CompiledLogic, data: Arc<Value>, ) -> Result<Value>
Evaluates compiled logic with Arc-wrapped data.
Use this method when you already have data in an Arc to avoid re-wrapping.
For owned data, use evaluate_owned instead.
§Arguments
compiled- The compiled logic to evaluatedata- The data context wrapped in anArc
§Returns
The evaluation result, or an error if evaluation fails.
Sourcepub fn evaluate_owned(
&self,
compiled: &CompiledLogic,
data: Value,
) -> Result<Value>
pub fn evaluate_owned( &self, compiled: &CompiledLogic, data: Value, ) -> Result<Value>
Evaluates compiled logic with owned data.
This is a convenience method that wraps the data in an Arc before evaluation.
If you already have Arc-wrapped data, use evaluate instead.
§Arguments
compiled- The compiled logic to evaluatedata- The owned data context
§Returns
The evaluation result, or an error if evaluation fails.
§Example
use datalogic_rs::DataLogic;
use serde_json::json;
let engine = DataLogic::new();
let logic = json!({"var": "name"});
let compiled = engine.compile(&logic).unwrap();
let data = json!({"name": "Alice"});
let result = engine.evaluate_owned(&compiled, data).unwrap();
assert_eq!(result, json!("Alice"));Sourcepub fn evaluate_json(&self, logic: &str, data: &str) -> Result<Value>
pub fn evaluate_json(&self, logic: &str, data: &str) -> Result<Value>
Convenience method for evaluating JSON strings directly.
This method combines compilation and evaluation in a single call. For repeated evaluations, compile once and reuse the compiled logic.
§Arguments
logic- JSON logic as a stringdata- Data context as a JSON string
§Returns
The evaluation result, or an error if parsing or evaluation fails.
§Example
use datalogic_rs::DataLogic;
let engine = DataLogic::new();
let result = engine.evaluate_json(
r#"{"==": [{"var": "x"}, 5]}"#,
r#"{"x": 5}"#
).unwrap();
assert_eq!(result, serde_json::json!(true));Sourcepub fn evaluate_node(
&self,
node: &CompiledNode,
context: &mut ContextStack,
) -> Result<Value>
pub fn evaluate_node( &self, node: &CompiledNode, context: &mut ContextStack, ) -> Result<Value>
Evaluates a compiled node using OpCode dispatch.
This is the core evaluation method that handles:
- Static values
- Arrays
- Built-in operators (via OpCode)
- Custom operators
- Structured objects (in preserve mode)
§Arguments
node- The compiled node to evaluatecontext- The context stack containing data and metadata
§Returns
The evaluation result, or an error if evaluation fails.
Sourcepub fn evaluate_node_cow<'a>(
&self,
node: &'a CompiledNode,
context: &mut ContextStack,
) -> Result<Cow<'a, Value>>
pub fn evaluate_node_cow<'a>( &self, node: &'a CompiledNode, context: &mut ContextStack, ) -> Result<Cow<'a, Value>>
Evaluate a compiled node, returning a Cow to avoid cloning literal values.
For CompiledNode::Value nodes (constants/literals), returns a borrowed reference
to the pre-compiled value without cloning. For all other node types, performs full
evaluation and returns the owned result.
Sourcepub fn evaluate_json_with_trace(
&self,
logic: &str,
data: &str,
) -> Result<TracedResult>
pub fn evaluate_json_with_trace( &self, logic: &str, data: &str, ) -> Result<TracedResult>
Evaluate JSON logic with execution trace for debugging.
This method compiles and evaluates JSONLogic while recording each execution step for replay in debugging UIs.
§Arguments
logic- JSON logic as a stringdata- Data context as a JSON string
§Returns
A TracedResult containing the result, expression tree, and execution steps.
§Example
use datalogic_rs::DataLogic;
let engine = DataLogic::new();
let result = engine.evaluate_json_with_trace(
r#"{">=": [{"var": "age"}, 18]}"#,
r#"{"age": 25}"#
).unwrap();
println!("Result: {}", result.result);
println!("Steps: {}", result.steps.len());Sourcepub fn evaluate_node_traced(
&self,
node: &CompiledNode,
context: &mut ContextStack,
collector: &mut TraceCollector,
node_id_map: &HashMap<usize, u32>,
) -> Result<Value>
pub fn evaluate_node_traced( &self, node: &CompiledNode, context: &mut ContextStack, collector: &mut TraceCollector, node_id_map: &HashMap<usize, u32>, ) -> Result<Value>
Evaluate a compiled node with tracing.
This method records each step of the evaluation for debugging.