---
title: 'Rust'
description: "Gunakan json-eval-rs secara langsung di proyek Rust milikmu. Crate ini menyediakan mesin evaluasi penuh tanpa beban FFI, dengan API yang aman (type-safe) berbasis serde_json."
navigation:
  icon: 'i-simple-icons-rust'
seo:
  title: 'Rust'
  description: "Gunakan json-eval-rs secara langsung di proyek Rust milikmu. Crate ini menyediakan mesin evaluasi penuh tanpa beban FFI, dengan API yang aman (type-safe) berbasis serde_json."
---

## Instalasi

Tambahkan crate ini ke proyekmu:

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

Atau tambahkan secara manual di `Cargo.toml`:

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

### Fitur Opsional

| Fitur | Deskripsi |
|---|---|
| `serialize` | Mengaktifkan serialisasi untuk instance `JSONEval` |
| `ffi` | Membuka lapisan FFI yang kompatibel dengan C untuk interop native |
| `wasm` | Mengompilasi ke WebAssembly lewat `wasm-bindgen` |



## Mulai Cepat

```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 wajib diisi" },
                    "pattern": {
                        "value": "^[^@]+@[^@]+\\.[^@]+$",
                        "message": "Format email tidak valid"
                    }
                }
            }
        }
    }"#;

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

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

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

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

    Ok(())
}
```

## Referensi API

### Constructor

#### `JSONEval::new`

Membuat instance baru dengan membaca dan menyusun (compile) schema dari string JSON.

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

- **`schema`** — String definisi schema JSON.
- **`context`** — Konteks eksternal opsional (misal: info user, env vars) dalam bentuk string JSON.
- **`data`** — Data awal opsional dalam bentuk string JSON.

#### `JSONEval::new_from_msgpack`

Membuat instance baru dari schema yang dienkode dengan MessagePack. Schema MessagePack bisa dibaca ~2–3× lebih cepat daripada JSON.

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

#### `JSONEval::with_parsed_schema`

Membuat instance dari `ParsedSchema` yang sudah dibaca sebelumnya. Ini adalah cara yang disarankan untuk beban kerja tinggi — baca schema sekali, gunakan berkali-kali.

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

---

### Metode Core

#### `evaluate`

Mengevaluasi schema terhadap data baru, memperbarui status schema internal yang sudah dievaluasi.

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

- **`data`** — String data JSON.
- **`context`** — Konteks terbaru (opsional).
- **`paths`** — Daftar kolom tertentu untuk [Evaluasi Selektif](/advance-guide/optimize-selective-evaluation) (opsional). Bisa menggunakan dot notation (`"user.email"`), JSON Pointer (`"/properties/email"`), atau schema pointer (`"#/properties/email"`).
- **`token`** — Token pembatalan opsional untuk membatalkan proses secara aman.

#### `validate`

Memvalidasi data terhadap aturan yang ada di schema. Mengembalikan error yang terstruktur tanpa mengubah status evaluasi.

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

Isi dari `ValidationResult`:
- `has_error: bool`
- `errors: Vec<ValidationError>` — masing-masing berisi `path` dan `message`

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

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

#### `evaluate_dependents`

Mengevaluasi ulang hanya kolom yang bergantung pada perubahan di jalur (path) tertentu. Sangat cocok untuk pembaruan form yang reaktif.

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

- **`changed_paths`** — Jalur yang berubah (misal: `["user.email"]`).
- **`re_evaluate`** — Jika `true`, akan menjalankan fungsi `evaluate` penuh setelah menghitung ketergantungan.

---

### Pengambilan Data Schema

Metode-metode untuk membaca hasil evaluasi setelah memanggil `evaluate`.

```rust
// Schema lengkap sebagai serde_json::Value
pub fn get_evaluated_schema(&self, skip_layout: bool) -> Value

// Schema tanpa objek $params
pub fn get_evaluated_schema_without_params(&self, skip_layout: bool) -> Value

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

// Ambil jalur tertentu (misal: "#/properties/email")
pub fn get_evaluated_schema_by_path(&self, path: &str, skip_layout: bool) -> Option<Value>

// Ambil beberapa jalur sekaligus
pub fn get_evaluated_schema_by_paths(
    &self,
    paths: &[String],
    skip_layout: bool,
) -> Value

// Ambil hasil akhir di root `.value`
pub fn get_schema_value(&self) -> Option<Value>
```

---

### Memuat Ulang Schema

Mengganti schema pada instance yang sudah ada tanpa perlu membuatnya dari awal.

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

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

// Dari Arc<ParsedSchema> yang sudah dibaca
pub fn reload_schema_parsed(
    &mut self,
    parsed: Arc<ParsedSchema>,
    context: Option<&str>,
    data: Option<&str>,
) -> Result<(), String>

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

---

### Metode Lainnya

**`set_timezone_offset`**
Mengatur perbedaan waktu yang digunakan untuk operator waktu seperti `today`, `now`, dan `dateformat`.

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

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

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

**`resolve_layout`**
Menyelesaikan node UI `$layout` secara terpisah dari siklus evaluasi utama.

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

---

### Cache Evaluasi

```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  // { entri, hit, miss, hit_rate }
pub fn get_cache_length(&self) -> usize
```

---

### Metode Subform

Untuk mengevaluasi schema item array yang terisolasi (Subform).

#### `evaluate_subform`

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

- **`subform_path`** — Referensi schema ke kolom array (misal: `"#/line_items"`).
- **`data`** — Data untuk satu item yang sedang dievaluasi.
- **`paths`** — Jalur opsional untuk evaluasi selektif di dalam 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>
```

## Caching & Performa

Untuk aplikasi dengan trafik tinggi (misal: web server), baca schema sekali saja menggunakan `ParsedSchema` dan bagikan ke handler permintaan menggunakan `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();

    // Baca sekali — ini akan menyusun semua ekspresi JSON Logic
    let parsed = Arc::new(
        ParsedSchema::parse(&schema_str).map_err(|e| e.to_string())?
    );

    // Di setiap request: buat JSONEval baru dari ParsedSchema yang sudah di-cache.
    // Arc::clone sangat ringan karena hanya menambah hitungan pointer — tidak ada data yang dikopi.
    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(())
}
```

### Keamanan Thread

Instance `JSONEval` **tidak** bersifat `Send` + `Sync` untuk operasi tulis. Untuk skenario server bersamaan (concurrent):

- ✅ Buat satu `JSONEval` **per request** menggunakan `JSONEval::with_parsed_schema`.
- ✅ Bagikan `Arc<ParsedSchema>` ke thread lain dengan aman.
- ❌ Jangan gunakan satu `JSONEval` yang sama (mutable) di banyak thread sekaligus.

### Schema MessagePack

Schema biner yang sudah disusun menawarkan proses pembacaan yang lebih cepat dengan performa evaluasi yang sama:

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

Atau menggunakan `ParsedSchema`:

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

## Dukungan Platform

- **Edisi Rust**: 2021
- **MSRV**: 1.70+
- **Target**: `x86_64-unknown-linux-gnu`, `x86_64-pc-windows-msvc`, `x86_64-apple-darwin`, `aarch64-apple-darwin`, `wasm32-unknown-unknown` (dengan fitur `wasm`)
