pub struct Engine { /* private fields */ }Expand description
JSONLogic compile/evaluate engine.
Holds the immutable engine state — registered crate::CustomOperator
implementations, the EvaluationConfig, the templating, folding and
family settings — and exposes the public surface for parsing
rules (Self::compile), evaluating them (Self::eval /
Self::eval_str, Self::eval_into), and opening hot-loop
sessions (Self::session).
Enabling the trace feature also exposes Self::trace for traced sessions.
Engine is Send + Sync (every field is); the typical pattern is to
build one at startup, wrap it in Arc<Engine>, and clone the Arc
across threads or async tasks.
§Example
use datalogic_rs::Engine;
// 1. Build the engine.
let engine = Engine::new();
// 2. Compile a rule once.
let logic = engine
.compile(r#"{"if": [{">=": [{"var": "age"}, 18]}, "adult", "minor"]}"#)
.unwrap();
// 3. Evaluate against many inputs (here via `Session::eval_str`;
// drop to `Engine::evaluate` if you want zero-copy borrowed results).
let mut session = engine.session();
for age in [12, 18, 42] {
let payload = format!(r#"{{"age": {age}}}"#);
let result = session.eval_str(&logic, &payload).unwrap();
assert!(result == "\"adult\"" || result == "\"minor\"");
session.reset();
}§Choosing an evaluate method
Start here. Use Self::eval_str for one-shot calls. Switch
to crate::Session once you’re evaluating the same compiled rule
many times — it reuses one arena instead of allocating per call.
Drop down to Self::evaluate only when you’re managing your own
bumpalo::Bump (custom pools, integration with arena-aware
downstream code).
Result-shape suffixes work the same on every tier: (none) returns
datavalue::OwnedDataValue, _str returns String (JSON),
_into::<T> returns T: DeserializeOwned (requires serde_json).
The raw Self::evaluate is the only method that exposes
&'a DataValue<'a> and a caller-owned &Bump.
Three tiers, in order of caller control:
| Method | Arena ownership | Result type | When to use |
|---|---|---|---|
Self::eval / Self::eval_str / Self::eval_into | engine creates a fresh Bump::with_capacity(4096) per call | OwnedDataValue / String / T | One-shot. Any caller that doesn’t want to think about arenas. Allocates each call — for hot loops, drop to Session. |
crate::Session::eval / crate::Session::eval_str / crate::Session::eval_into / crate::Session::eval_borrowed | session-owned Bump, caller calls crate::Session::reset between batches | owned / String / T / borrowed &'a DataValue<'a> | Hot loop with a long-lived engine. The Session hides bumpalo from the call site and pre-sizes the arena via crate::Session::reset_with_capacity when needed. |
Self::evaluate | caller-passed &Bump; library never resets | &'a DataValue<'a> (borrowed) | Zero-copy result paths, custom pool/allocator strategies, integration with arena-aware downstream code. |
All routes share the same dispatcher; the differences are who owns the arena, what the result type looks like, and whether the boundary parses / serialises JSON for you. There is no perf difference between the arena-aware paths once the bump is warm.
See the crate-level docs for the two-phase architecture, threading
model, and walk-through examples; see the Session and
EvaluationConfig rustdoc for arena-management and behaviour-tuning
options respectively.
Implementations§
Source§impl Engine
impl Engine
Sourcepub fn builder() -> EngineBuilder
pub fn builder() -> EngineBuilder
Start a crate::EngineBuilder for fluent construction.
Use the builder when you need a non-default EvaluationConfig,
templating mode, or pre-registered custom operators.
For a stock engine, Self::new is shorter.
Sourcepub fn to_builder(&self) -> EngineBuilder
pub fn to_builder(&self) -> EngineBuilder
A builder that starts from this engine: the same custom operators,
config, templating mode, template key escape and folding setting.
Change what differs and call build
for a new engine; this one is untouched.
Both engines share each operator instance (and any state it holds), so a host that rebuilds on every reload does not register its operators again. Rules compiled on this engine still evaluate on the new one, looking their custom operators up by name.
§Example
use datalogic_rs::{Engine, EvaluationConfig, MissingVar};
let running = Engine::new();
let reloaded = running
.to_builder()
.with_config(EvaluationConfig::default().with_missing_var(MissingVar::Error))
.build();
assert!(reloaded.eval_str(r#"{"var": "x"}"#, "{}").is_err());
assert_eq!(running.eval_str(r#"{"var": "x"}"#, "{}").unwrap(), "null");Sourcepub fn session(&self) -> Session<'_>
pub fn session(&self) -> Session<'_>
Open a crate::Session handle that owns a reusable arena and
returns owned results, so callers don’t need to manage a
bumpalo::Bump themselves.
Use this when you want the throughput of arena reuse without the
lifetime juggling of Self::evaluate. Results are deep-cloned out
of the arena before returning, so they survive later calls and resets.
The session does not auto-reset: allocations accumulate until you
call crate::Session::reset, which you should do between logical
batches to bound peak memory in long-running services.
§Example
use datalogic_rs::Engine;
let engine = Engine::new();
let compiled = engine.compile(r#"{"+": [{"var": "x"}, 1]}"#).unwrap();
let mut session = engine.session();
let result = session.eval_str(&compiled, r#"{"x": 41}"#).unwrap();
assert_eq!(result, "42");Sourcepub fn new() -> Self
pub fn new() -> Self
Creates a new Engine with all built-in operators.
The engine includes every built-in operator compiled into this build
(84 canonical operators with all operator features on; see
Self::builtin_operator_names), dispatched via OpCode.
Templating mode is disabled by default. For non-default
configuration (custom EvaluationConfig, templating mode,
pre-registered custom operators) prefer Self::builder.
§Example
use datalogic_rs::Engine;
let engine = Engine::new();Sourcepub fn config(&self) -> &EvaluationConfig
pub fn config(&self) -> &EvaluationConfig
Gets a reference to the current evaluation configuration.
Sourcepub fn has_custom_operator(&self, name: &str) -> bool
pub fn has_custom_operator(&self, name: &str) -> bool
Checks if a custom operator with the given name is registered.
Operator registration is builder-only; this is a read-only check
against the frozen set produced by crate::EngineBuilder.
Sourcepub fn custom_operator_info(&self, name: &str) -> Option<CustomOperatorInfo>
pub fn custom_operator_info(&self, name: &str) -> Option<CustomOperatorInfo>
What the custom operator registered as name declares about
itself (crate::CustomOperator::info), or None when no custom
operator has that name. Built-ins are described by
Self::operators.
Sourcepub fn custom_operator_names(&self) -> impl Iterator<Item = &str>
pub fn custom_operator_names(&self) -> impl Iterator<Item = &str>
Iterator over the names of every custom operator registered on this engine (built-ins are not included). Order is unspecified (HashMap iteration order). Useful for tooling, UIs, and tests that need to introspect what’s available.
Sourcepub fn builtin_operator_names(
&self,
) -> impl Iterator<Item = &'static str> + use<>
pub fn builtin_operator_names( &self, ) -> impl Iterator<Item = &'static str> + use<>
Iterator over every built-in operator name this build evaluates:
the JSONLogic baseline plus whichever extension families
(ext-string, datetime, ext-control, …) were compiled in.
The list is derived from the same table the compiler resolves
operator keys against, so it cannot drift from dispatch. It
includes input aliases (var for val, ?: for if, match
for switch) because those keys are live calls too; order is
canonical name first, then its aliases, per operator.
Custom registrations are not included; see
Self::custom_operator_names. The union of the two is the full
vocabulary of this engine. A custom operator registered under a
built-in name is never reached: built-in resolution wins at
compile time.
Under templating mode an unknown key is not an error (the object echoes back as data), so this is the vocabulary authoring-side tooling needs to tell a live call from a literal.
§Example
use datalogic_rs::Engine;
let engine = Engine::new();
let names: Vec<&str> = engine.builtin_operator_names().collect();
assert!(names.contains(&"val"));
assert!(names.contains(&"var")); // alias of `val`
assert!(!names.contains(&"lenght"));Sourcepub fn operators(&self) -> impl Iterator<Item = OperatorInfo> + use<>
pub fn operators(&self) -> impl Iterator<Item = OperatorInfo> + use<>
Every built-in operator compiled into this build, described by its operator-table row: name and aliases, family and gating feature, declared argument counts, whether it reads the data context, its effect, its cost class, and which argument (if any) runs under a pushed frame.
Read from the same table that drives compilation, dispatch and the
optimizer, so it cannot drift from what the engine does. Custom
operators are not included; see Self::custom_operator_names.
§Example
use datalogic_rs::{Engine, ScopedArg};
let engine = Engine::new();
let map = engine.operators().find(|op| op.name == "map").unwrap();
assert_eq!(map.family, "Core");
assert_eq!(map.feature, None);
assert_eq!(map.scoped_arg, Some(ScopedArg::Index(1)));
let val = engine.operators().find(|op| op.name == "val").unwrap();
assert_eq!(val.aliases, ["var"]);
assert!(val.reads_context);Sourcepub fn compile<R: IntoLogic>(&self, rule: R) -> Result<Logic>
pub fn compile<R: IntoLogic>(&self, rule: R) -> Result<Logic>
Compile a rule source into reusable Logic.
rule accepts any crate::IntoLogic shape: &str (JSON-parsed),
&OwnedDataValue / OwnedDataValue (cloned/moved), or
&serde_json::Value (gated on serde_json). For cross-thread
sharing prefer Self::compile_arc.
§Example
use datalogic_rs::Engine;
let engine = Engine::new();
let compiled = engine.compile(r#"{"==": [{"var": "x"}, 1]}"#).unwrap();Sourcepub fn check<R: IntoLogic>(&self, rule: R, mode: CheckMode) -> Vec<Diagnostic>
pub fn check<R: IntoLogic>(&self, rule: R, mode: CheckMode) -> Vec<Diagnostic>
Check rule without compiling it: every problem the engine can see
before it runs, in rule order, each located by a JSON Pointer.
An Error is something that will fail: a
rule that does not compile (an object with several keys outside
templating mode), or a call that fails whenever it runs (an unknown
operator, and / or / if without an argument array, an argument
count the operator rejects, a literal timezone that does not exist).
A Warning runs, but probably not as
meant: arguments an operator never evaluates, or in a template an
output key one edit away from an operator name.
Unlike Self::compile, which stops at the first problem and
leaves call errors to evaluation, this reports them all, including
those in branches a given input never reaches. mode chooses
strict or templating mode for this check (see crate::CheckMode).
§Example
use datalogic_rs::{CheckMode, DiagnosticCode, Engine};
let engine = Engine::new();
let diags = engine.check(r#"{"if": [true, {"vr": "x"}, {"map": [1]}]}"#, CheckMode::Engine);
assert_eq!(diags.len(), 2);
assert_eq!(diags[0].code, DiagnosticCode::UnknownOperator);
assert_eq!(diags[0].pointer, "/if/1");
assert!(diags[0].message.contains("did you mean `var`"));
assert_eq!(diags[1].code, DiagnosticCode::ArgumentCount);Sourcepub fn compile_checked<R: IntoLogic>(
&self,
rule: R,
) -> Result<Logic, CompileError>
pub fn compile_checked<R: IntoLogic>( &self, rule: R, ) -> Result<Logic, CompileError>
Self::compile, refusing a rule that Self::check finds any
error in: strict up front, where compile leaves a call that cannot
succeed to fail at evaluation. The error carries every diagnostic,
warnings included. A rule with only warnings compiles.
§Errors
crate::CompileError listing the diagnostics.
Sourcepub fn compile_template<R: IntoLogic>(&self, rule: R) -> Result<Logic>
Available on crate feature templating only.
pub fn compile_template<R: IntoLogic>(&self, rule: R) -> Result<Logic>
templating only.Compile rule in templating mode, whatever mode the engine was
built with: a multi-key object is an output template and an
unknown operator key is an output field, as on an engine built
with_templating(true).
The engine’s custom operators, template key escape and folding
setting apply as usual.
With Self::compile_strict this lets one engine, with one set of
custom operators, both check rules strictly and compile output
templates, instead of a host building an engine per mode.
§Example
use datalogic_rs::Engine;
let engine = Engine::new();
let template = r#"{"user": {"var": "name"}, "source": "api"}"#;
assert!(engine.compile(template).is_err());
let logic = engine.compile_template(template).unwrap();
let out = engine.session().eval_str(&logic, r#"{"name": "ana"}"#).unwrap();
assert_eq!(out, r#"{"user":"ana","source":"api"}"#);Sourcepub fn compile_strict<R: IntoLogic>(&self, rule: R) -> Result<Logic>
pub fn compile_strict<R: IntoLogic>(&self, rule: R) -> Result<Logic>
Compile rule outside templating mode, whatever mode the engine
was built with: a multi-key object is an error, and an unknown
operator is not an output field, exactly as on an engine built
without templating. The engine’s custom operators and folding
setting apply as usual.
On an engine built without templating this is Self::compile.
§Example
use datalogic_rs::Engine;
let engine = Engine::builder().with_templating(true).build();
let typo = r#"{"user": {"var": "name"}, "sourec": "api"}"#;
assert!(engine.compile(typo).is_ok()); // an output template
assert!(engine.compile_strict(typo).is_err()); // not a ruleSourcepub fn compile_arc<R: IntoLogic>(&self, rule: R) -> Result<Arc<Logic>>
pub fn compile_arc<R: IntoLogic>(&self, rule: R) -> Result<Arc<Logic>>
Compile and wrap in an Arc in one call. Convenience for the
dominant cross-thread-sharing pattern; equivalent to
Arc::new(engine.compile(rule)?).
Sourcepub fn trace(&self) -> TracedSession<'_>
Available on crate feature trace only.
pub fn trace(&self) -> TracedSession<'_>
trace only.Open a crate::TracedSession over this engine. Calls made through
the session collect a per-call trace; the bare eval* methods on
Engine itself pay no trace overhead.
Available only when the crate is built with feature = "trace".
§Trace coverage
The session’s one-shot crate::TracedSession::eval_str compiles
the rule internally with optimization disabled, so every operator
in the rule surfaces a trace step.
The pre-compiled paths (crate::TracedSession::eval taking a
&Logic) inherit whatever shape that Logic was compiled into —
constant sub-expressions folded by Self::compile won’t appear,
since there is no operator left to execute. Use eval_str for
full coverage on a one-shot run.
§Example
use datalogic_rs::Engine;
let engine = Engine::new();
let run = engine
.trace()
.eval_str(r#"{"+": [1, 2]}"#, "null");
assert_eq!(run.result.unwrap(), "3");
// run.steps is the per-node execution log;
// run.expression_tree is the rule's compile-time tree shape.Sourcepub fn evaluate<'a, D: EvalInput<'a>>(
&self,
compiled: &'a Logic,
data: D,
arena: &'a Bump,
) -> Result<&'a DataValue<'a>>
pub fn evaluate<'a, D: EvalInput<'a>>( &self, compiled: &'a Logic, data: D, arena: &'a Bump, ) -> Result<&'a DataValue<'a>>
Evaluate compiled logic against arena-resident data — raw tier.
The caller owns the bumpalo::Bump lifecycle and may reset()
it between calls; the returned &DataValue<'a> borrows from the
arena, so it must be dropped before the next reset (enforced by
the borrow checker). For ergonomic owned/typed/JSON-string output,
prefer Self::eval / Self::eval_str
/ Self::eval_into.
§Example
use bumpalo::Bump;
use datalogic_rs::{Engine, DataValue};
let engine = Engine::new();
let compiled = engine.compile(r#"{"+": [{"var": "x"}, 2]}"#).unwrap();
let arena = Bump::new();
let data = DataValue::from_str(r#"{"x": 40}"#, &arena).unwrap();
let result = engine.evaluate(&compiled, data, &arena).unwrap();
assert_eq!(result.as_i64(), Some(42));data accepts any input shape understood by crate::EvalInput:
&'a DataValue<'a> (zero-cost passthrough), DataValue<'a>
(single arena alloc), &str (JSON-parsed), &OwnedDataValue
(deep-borrowed), &ParsedData (zero-cost
passthrough of a parse-once handle), or &serde_json::Value
(gated on serde_json).
Sourcepub fn resolve_ops_budget(&self, explicit: Option<u64>) -> u64
Available on crate feature budget only.
pub fn resolve_ops_budget(&self, explicit: Option<u64>) -> u64
budget only.The budget a metered call runs under: explicit when the caller
gave one, else the engine-wide
EvaluationConfig::ops_budget,
else unbounded (u64::MAX).
This is the precedence Self::evaluate applies implicitly, made
available to callers of Self::evaluate_metered — the language
bindings’ “omit the budget to use the engine’s” forms all resolve
through here, so a rule metered from any of them reports the same
number.
Sourcepub fn evaluate_metered<'a, D: EvalInput<'a>>(
&self,
compiled: &'a Logic,
data: D,
arena: &'a Bump,
budget: u64,
) -> Result<Metered<&'a DataValue<'a>>>
Available on crate feature budget only.
pub fn evaluate_metered<'a, D: EvalInput<'a>>( &self, compiled: &'a Logic, data: D, arena: &'a Bump, budget: u64, ) -> Result<Metered<&'a DataValue<'a>>>
budget only.Evaluate under an explicit operation budget, reporting what the evaluation spent.
Same evaluation as Self::evaluate, with two differences: the
budget argument overrides
EvaluationConfig::ops_budget
for this call, and the result carries the operation count next to
the value. Pass u64::MAX to meter without bounding.
§What the count means
“Nodes dispatched at runtime, plus whatever operators charge” — not “nodes in the source”. Concretely:
- 1 per dispatched node. Literals cost 0 (they return before dispatch), and so do constant-folded subtrees — the compiler already did that work, and charging for it would make the count depend on whether folding was enabled.
- 1 per item an iterator examines, charged by
map,filter,reduce, the quantifiers,sortand friends as soon as the source is resolved. This is what keeps the number honest when a compile-time fast path evaluates a predicate inline instead of dispatching its body: the iteration costs at least its input length whichever path runs. - 1 per item a collection operator copies, examines or
compares, charged before the work:
mergeper item of each array argument,inper item of an array haystack,missing/missing_someper path of a path list from data,keys/values/entriesper key, a steppedsliceper item produced,distinct/group_byper comparison,sortn·⌈log₂ n⌉, and one-argument arithmetic per array item. Iterating an object costs 1 per key. - The structural walk of an equality between containers: 1 per
array element,
|a| x |b|per object level, for each level the comparison reaches. - 1 per whole 64 bytes of string a string operator reads (
cat,substr,upper,lower,trim,length,split,inon a string,starts_with/ends_with, stringslice), so strings under 64 bytes are free. - Whatever an operator charges for itself. The tensor family
prices each operator at
max(elements read, elements produced), before it allocates. Acrate::CustomOperatorthat walks a large input should do the same viaEvalContext::charge. - A CSE-memoised subtree is charged once, on the evaluation that fills the slot.
The count is deterministic for a pinned crate version and a given
(rule, data) pair, whichever evaluation path runs: an iterator fast
path charges what the general path would for the same data, so
tracing and MissingVar::Error, which
turn the fast paths off, leave it unchanged. It is not stable
across versions: a new fold changes what gets dispatched. Budget
for the work you want to allow, not for an exact number you
measured.
§Example
use bumpalo::Bump;
use datalogic_rs::{Engine, ErrorCode};
let engine = Engine::new();
let compiled = engine.compile(r#"{"map": [{"var": "xs"}, {"*": [{"var": ""}, 2]}]}"#).unwrap();
let arena = Bump::new();
let metered = engine
.evaluate_metered(&compiled, r#"{"xs": [1, 2, 3]}"#, &arena, u64::MAX)
.unwrap();
assert_eq!(metered.value.to_json_string(), "[2,4,6]");
assert!(metered.ops >= 3, "at least one operation per item");
// Too tight a budget refuses the evaluation instead of running it.
let err = engine
.evaluate_metered(&compiled, r#"{"xs": [1, 2, 3]}"#, &arena, 2)
.unwrap_err();
assert_eq!(err.code(), ErrorCode::BudgetExceeded);§Errors
ErrorKind::BudgetExceeded
when the rule charges past budget, plus every error
Self::evaluate can return. To observe the operations spent
even when evaluation fails, call Self::evaluate_metered_report.
Sourcepub fn evaluate_metered_report<'a, D: EvalInput<'a>>(
&self,
compiled: &'a Logic,
data: D,
arena: &'a Bump,
budget: u64,
) -> Metered<Result<&'a DataValue<'a>>>
Available on crate feature budget only.
pub fn evaluate_metered_report<'a, D: EvalInput<'a>>( &self, compiled: &'a Logic, data: D, arena: &'a Bump, budget: u64, ) -> Metered<Result<&'a DataValue<'a>>>
budget only.Failure-inclusive counterpart to Self::evaluate_metered:
evaluates under budget and returns a Metered report whose
ops is populated whether evaluation succeeds (value: Ok(...))
or fails (value: Err(...)).
Hosts that reserve capacity from a shared parent ledger before an
expression runs can reconcile the reservation against report.ops
on both successful and failed evaluations, instead of either
dropping failed work or conservatively charging the entire
reservation.
§Charge semantics on failure
- Ordinary runtime failures (
Thrown,VariableNotFound,TypeError,ArithmeticError,Custom, …):report.opsis the exact number of operations charged before the failing node or operator aborted. Because every node and operator charges before doing its work, the failing node’s own dispatch charge (and any pre-allocation charge it made before raising) is included. Thecrate::Errorinreport.valueretains its fullError::code,Error::operator, andError::node_idsbreadcrumb. - Budget exhaustion
(
ErrorKind::BudgetExceeded { budget, spent }): every charge is added to the running counter before comparing againstbudget, soreport.opsequalsspent— the attempted total that crossed the ceiling. Do not addreport.opsandspenttogether (they are the same counter); a host debiting a reserved slice of sizebudgetcan debitreport.ops.min(budget)for bounded work orreport.opsfor attempted work. - Pre-dispatch failures (input adaptation / JSON parse errors
from
data, or exceedingmax_recursion_depthat the boundary): no node is dispatched, soreport.ops == 0.
§Example
use bumpalo::Bump;
use datalogic_rs::{Engine, ErrorCode, Metered};
let engine = Engine::new();
let compiled = engine.compile(r#"{"/": [1, {"var": "zero"}]}"#).unwrap();
let arena = Bump::new();
let Metered { value, ops } = engine
.evaluate_metered_report(&compiled, r#"{"zero": 0}"#, &arena, 100);
let err = value.unwrap_err();
assert_eq!(err.code(), ErrorCode::Thrown);
assert_eq!(err.operator(), Some("/"));
assert_eq!(ops, 2, "the `/` and the `var` were dispatched before division failed");Sourcepub fn truthy(&self, value: &DataValue<'_>) -> bool
pub fn truthy(&self, value: &DataValue<'_>) -> bool
Apply the engine’s configured truthiness rules
(crate::TruthyEvaluator) to an evaluated value.
This is the same coercion if / and / or / ! apply to
their operands, exposed so callers (and bindings) can collapse
any rule result to a boolean without re-implementing the
engine’s configured semantics.
§Example
use bumpalo::Bump;
use datalogic_rs::Engine;
let engine = Engine::new();
let compiled = engine.compile(r#"{"var": "items"}"#).unwrap();
let arena = Bump::new();
let result = engine.evaluate(&compiled, r#"{"items": [1]}"#, &arena).unwrap();
assert!(engine.truthy(result));Sourcepub fn truthy_of<V: TruthyInput>(&self, value: V) -> bool
pub fn truthy_of<V: TruthyInput>(&self, value: V) -> bool
Self::truthy for a value in any representation the host holds:
&OwnedDataValue, &serde_json::Value, &ParsedData or
&DataValue (see crate::TruthyInput).
Use it instead of re-implementing truthiness on a result: the
answer follows the engine’s crate::TruthyEvaluator, and under
the default rules an empty object is falsy, like an empty array,
which hand-written checks often miss.
§Example
use datalogic_rs::Engine;
use serde_json::json;
let engine = Engine::new();
let result: serde_json::Value = engine
.eval_into(r#"{"var": "claims"}"#, &json!({"claims": {}}))
.unwrap();
assert!(!engine.truthy_of(&result));
assert!(engine.truthy_of(&json!({"sub": "ana"})));Sourcepub fn eval<R, D>(&self, rule: R, data: D) -> Result<OwnedDataValue>where
R: IntoLogic,
D: OwnedInput,
pub fn eval<R, D>(&self, rule: R, data: D) -> Result<OwnedDataValue>where
R: IntoLogic,
D: OwnedInput,
One-shot evaluation returning datavalue::OwnedDataValue.
Compiles rule, parses data, evaluates against a fresh
per-call arena, and deep-clones the result out. For the same
rule run repeatedly, escalate to Self::compile + a
Session.
§Example
use datalogic_rs::Engine;
let engine = Engine::new();
let result = engine.eval(
r#"{"+": [{"var": "x"}, 1]}"#,
r#"{"x": 41}"#,
).unwrap();
assert_eq!(result.as_i64(), Some(42));Sourcepub fn eval_str<R, D>(&self, rule: R, data: D) -> Result<String>where
R: IntoLogic,
D: OwnedInput,
pub fn eval_str<R, D>(&self, rule: R, data: D) -> Result<String>where
R: IntoLogic,
D: OwnedInput,
Sourcepub fn eval_into<T, R, D>(&self, rule: R, data: D) -> Result<T>
Available on crate feature serde_json only.
pub fn eval_into<T, R, D>(&self, rule: R, data: D) -> Result<T>
serde_json only.One-shot evaluation deserialised into a typed T: DeserializeOwned.
Use T = serde_json::Value for a JSON Value result; use a typed
struct for direct mapping. Internally routes through serde_json
(round-trips the result through a JSON value).
§Example
use datalogic_rs::Engine;
use serde_json::Value;
let engine = Engine::new();
let result: Value = engine.eval_into(
r#"{"+": [{"var": "x"}, 1]}"#,
r#"{"x": 41}"#,
).unwrap();
assert_eq!(result, Value::from(42));Sourcepub fn eval_as<O, R, D>(&self, rule: R, data: D) -> Result<O>
pub fn eval_as<O, R, D>(&self, rule: R, data: D) -> Result<O>
One-shot evaluation converting the result straight into O, any
crate::FromDataValue output: OwnedDataValue, a JSON
String, or a serde_json::Value (with serde_json).
For a serde_json::Value result this is one conversion, where
eval_into::<serde_json::Value> (with serde_json) builds the value and then
deserializes it into a second one.
use datalogic_rs::Engine;
let engine = Engine::new();
let user: serde_json::Value = engine
.eval_as(r#"{"var": "user"}"#, r#"{"user": {"id": 7}}"#)
.unwrap();
assert_eq!(user["id"], 7);