---
title: 'Rust'
description: "Use json-eval-rs natively in your Rust project via the serde_json API."
navigation:
  icon: 'i-simple-icons-rust'
seo:
  title: 'Rust'
  description: "Use json-eval-rs natively in your Rust project via the serde_json API."
---

## Installation

Add the crate to your project:

```bash
cargo add json-eval-rs
```

Or add it manually in `Cargo.toml`:

```toml
[dependencies]
json-eval-rs = "0.0.89"
```

### Optional Features

| Feature | Description |
|---|---|
| `serialize` | Enables serialization for `JSONEval` instances |
| `ffi` | Exposes a C-compatible FFI layer for native interop |
| `wasm` | Compiles to WebAssembly via `wasm-bindgen` |

```toml
```

## Quick Start

```rust
use json_eval_rs::JSONEval;

fn main() -> Result<(), String> {
    let schema = r#"{
        "type": "object",
        "properties": {
            "email": {
                "type": "string",
                "rules": {
                    "required": { "value": true, "message": "Email is required" },
                    "pattern": {
                        "value": "^[^@]+@[^@]+\\.[^@]+$",
                        "message": "Invalid email format"
                    }
                }
            }
        }
    }"#;

    let data = r#"{ "email": "invalid-email" }"#;

    // 1. Initialize
    let mut eval = JSONEval::new(schema, None, Some(data))
        .map_err(|e| e.to_string())?;

    // 2. Evaluate
    eval.evaluate(data, None, None, None)?;

    // 3. Get evaluated schema
    let result = eval.get_evaluated_schema(false);
    println!("{}", serde_json::to_string_pretty(&result).unwrap());

    Ok(())
}
```

## API Reference

### Constructors

#### `JSONEval::new`

Creates a new instance by parsing and compiling the schema from a JSON string.

```rust
pub fn new(
    schema: &str,
    context: Option<&str>,
    data: Option<&str>,
) -> Result<Self, serde_json::Error>
```

- **`schema`** — JSON schema definition string.
- **`context`** — Optional external context (e.g. user info, environment vars) as a JSON string.
- **`data`** — Optional initial data as a JSON string.

#### `JSONEval::new_from_msgpack`

Parses a MessagePack-encoded binary schema byte array.

```rust
pub fn new_from_msgpack(
    schema_msgpack: &[u8],
    context: Option<&str>,
    data: Option<&str>,
) -> Result<Self, String>
```

#### `JSONEval::with_parsed_schema`

Mounts an existing `ParsedSchema`. Use this method to share pre-parsed schemas across concurrent requests to avoid CPU overhead over identical structures.

```rust
pub fn with_parsed_schema(
    parsed: Arc<ParsedSchema>,
    context: Option<&str>,
    data: Option<&str>,
) -> Result<Self, String>
```

---

### Core Methods

#### `evaluate`

Evaluates the schema against new data, updating the internal evaluated schema state.

```rust
pub fn evaluate(
    &mut self,
    data: &str,
    context: Option<&str>,
    paths: Option<&[String]>,
    token: Option<&CancellationToken>,
) -> Result<(), String>
```

- **`data`** — JSON data string.
- **`context`** — Optional updated context.
- **`paths`** — Optional list of field paths for [Selective Evaluation](/advance-guide/optimize-selective-evaluation). Accepts dot notation (`"user.email"`), JSON Pointer (`"/properties/email"`), or schema pointer (`"#/properties/email"`).
- **`token`** — Optional cancellation token for cooperative cancellation.

#### `validate`

Validates data against rules defined in the schema. Returns structured errors without mutating evaluation state.

```rust
pub fn validate(
    &mut self,
    data: &str,
    context: Option<&str>,
) -> ValidationResult
```

`ValidationResult` fields:
- `has_error: bool`
- `errors: Vec<ValidationError>` — each with `path` and `message`

```rust
let result = eval.validate(data, None);

if result.has_error {
    for error in &result.errors {
        eprintln!("Field: {}, Error: {}", error.path, error.message);
    }
}
```

#### `evaluate_dependents`

Re-evaluates fields that exclusively depend on the `changed_paths`. Use this for targeted, reactive loop updates to skip iterating unaffected branches.

```rust
pub fn evaluate_dependents(
    &mut self,
    changed_paths: &[String],
    data: Option<&str>,
    context: Option<&str>,
    re_evaluate: bool,
) -> Result<Value, String>
```

- **`changed_paths`** — Paths that have changed (e.g. `["user.email"]`).
- **`re_evaluate`** — If `true`, triggers a full `evaluate` call after computing dependents.

---

### Schema Getters

Methods to read the resolved evaluation state after calling `evaluate`.

```rust
// Full schema as serde_json::Value
pub fn get_evaluated_schema(&self, skip_layout: bool) -> Value

// Schema without the $params object
pub fn get_evaluated_schema_without_params(&self, skip_layout: bool) -> Value

// Schema as raw MessagePack bytes (zero-copy)
pub fn get_evaluated_schema_msgpack(&self, skip_layout: bool) -> Result<Vec<u8>, String>

// Fetch specific path (e.g. "#/properties/email")
pub fn get_evaluated_schema_by_path(&self, path: &str, skip_layout: bool) -> Option<Value>

// Fetch multiple specific paths
pub fn get_evaluated_schema_by_paths(
    &self,
    paths: &[String],
    skip_layout: bool,
) -> Value

// Retrieve the resolved root `.value`
pub fn get_schema_value(&self) -> Option<Value>
```

---

### Schema Reloading

Hot-swap the schema on an existing instance without recreating it.

```rust
// From a new JSON string
pub fn reload_schema(
    &mut self,
    schema: &str,
    context: Option<&str>,
    data: Option<&str>,
) -> Result<(), String>

// From MessagePack bytes
pub fn reload_schema_msgpack(
    &mut self,
    schema_msgpack: &[u8],
    context: Option<&str>,
    data: Option<&str>,
) -> Result<(), String>

// From a pre-parsed Arc<ParsedSchema>
pub fn reload_schema_parsed(
    &mut self,
    parsed: Arc<ParsedSchema>,
    context: Option<&str>,
    data: Option<&str>,
) -> Result<(), String>

// From the global ParsedSchemaCache by key
pub fn reload_schema_from_cache(
    &mut self,
    cache_key: &str,
    context: Option<&str>,
    data: Option<&str>,
) -> Result<(), String>
```

---

### Misc Methods

**`set_timezone_offset`**
Sets the timezone offset used for temporal operators like `today`, `now`, and `dateformat`.

```rust
pub fn set_timezone_offset(&mut self, offset_minutes: Option<i32>)

// UTC+7 (Jakarta, Bangkok)
eval.set_timezone_offset(Some(420));

// Reset to UTC
eval.set_timezone_offset(None);
```

**`resolve_layout`**
Resolves `$layout` UI nodes independently from the main evaluation cycle.

```rust
pub fn resolve_layout(&mut self, evaluate: bool) -> Result<(), String>
```

---

### Evaluation Cache

```rust
pub fn enable_cache(&mut self)
pub fn disable_cache(&mut self)
pub fn clear_cache(&mut self)
pub fn is_cache_enabled(&self) -> bool
pub fn get_cache_stats(&self) -> CacheStats  // { entries, hits, misses, hit_rate }
pub fn get_cache_length(&self) -> usize
```

---

### Subform Methods

For evaluating isolated array item schemas (Subforms).

#### `evaluate_subform`

```rust
pub fn evaluate_subform(
    &mut self,
    subform_path: &str,
    data: &str,
    context: Option<&str>,
    paths: Option<&[String]>,
) -> Result<(), String>
```

- **`subform_path`** — Schema reference to the array field (e.g. `"#/line_items"`).
- **`data`** — Data for the single item being evaluated.
- **`paths`** — Optional paths for selective evaluation within the subform.

#### `evaluate_dependents_subform`

```rust
pub fn evaluate_dependents_subform(
    &mut self,
    subform_path: &str,
    changed_path: &str,
    data: Option<&str>,
    context: Option<&str>,
) -> Result<Value, String>
```

## Production caching

To maximize throughput on server applications, parse the schema logic array tree once using `ParsedSchema` and borrow it across request handlers using `Arc`.

```rust
use std::sync::Arc;
use json_eval_rs::{JSONEval, ParsedSchema};

fn main() -> Result<(), String> {
    let schema_str = std::fs::read_to_string("schema.json").unwrap();

    // Parse once — this compiles all JSON Logic expressions
    let parsed = Arc::new(
        ParsedSchema::parse(&schema_str).map_err(|e| e.to_string())?
    );

    // Per-request: create a new JSONEval from the cached ParsedSchema.
    // Arc::clone is a cheap pointer increment — no data is copied.
    let mut eval = JSONEval::with_parsed_schema(
        Arc::clone(&parsed),
        None,
        Some(request_data),
    )?;

    eval.evaluate(request_data, None, None, None)?;
    let result = eval.get_evaluated_schema(false);

    Ok(())
}
```

### Thread Safety

`JSONEval` instances are **not** `Send` + `Sync` for writing. For concurrent server scenarios:

- ✅ Create one `JSONEval` **per request** using `JSONEval::with_parsed_schema`.
- ✅ Share the `Arc<ParsedSchema>` across threads safely.
- ❌ Do not share a single mutable `JSONEval` across threads.

### MessagePack Schemas

Pre-compiled binary schemas offer faster parsing with identical evaluation performance:

```rust
let schema_bytes = std::fs::read("schema.bform").unwrap();
let mut eval = JSONEval::new_from_msgpack(&schema_bytes, None, Some(data))?;
```

Or using `ParsedSchema`:

```rust
let parsed = Arc::new(
    ParsedSchema::parse_msgpack(&schema_bytes).map_err(|e| e.to_string())?
);
```

## Platform Support

- **Rust Edition**: 2021
- **MSRV**: 1.70+
- **Targets**: `x86_64-unknown-linux-gnu`, `x86_64-pc-windows-msvc`, `x86_64-apple-darwin`, `aarch64-apple-darwin`, `wasm32-unknown-unknown` (with `wasm` feature)
