---
title: 'Compiled Logic Store'
description: "Penyimpanan logika terkompilasi global memungkinkan ekspresi logika yang sudah disusun untuk dibagikan ke berbagai instance JSONEval. Implementasi ini menggunakan cache global yang aman untuk multi-thread."
navigation:
  icon: 'i-ph-book-open'
seo:
  title: 'Compiled Logic Store'
  description: "Penyimpanan logika terkompilasi global memungkinkan ekspresi logika yang sudah disusun untuk dibagikan ke berbagai instance JSONEval. Implementasi ini menggunakan cache global yang aman untuk multi-thread."
---

## Gambaran Umum

## Arsitektur

### Komponen Utama

1. **`CompiledLogicId`** - Identifier ringan (u64) yang bisa dikirim melalui FFI.
2. **Global Store** - Penyimpanan yang aman untuk multi-thread (thread-safe) menggunakan `DashMap` dan atomic counters.
3. **Deduplikasi** - Logika yang sama jika dikompilasi berkali-kali akan mengembalikan ID yang sama (melalui hashing).

### Modul: `compiled_logic_store.rs`

```rust
pub struct CompiledLogicId(u64);

pub fn compile_logic(logic_json: &str) -> Result<CompiledLogicId, String>
pub fn get_compiled_logic(id: CompiledLogicId) -> Option<CompiledLogic>
pub fn get_store_stats() -> CompiledLogicStoreStats
```

## Contoh Penggunaan

### Penggunaan Dasar

::code-group
  ```rust [Rust]
  use json_eval_rs::{JSONEval, CompiledLogicId};
  use serde_json::json;

  // Buat instance pertama dan susun logikanya
  let mut eval1 = JSONEval::new(&schema, None, Some(&data))?;
  let logic_id = eval1.compile_logic(r#"{"*": [{"var": "x"}, 2]}"#)?;

  // Gunakan logika terkompilasi yang sama di instance berbeda
  let mut eval2 = JSONEval::new(&schema, None, Some(&data))?;
  let result = eval2.run_logic(logic_id, Some(&json!({"x": 10})), None)?;
  // hasil: 20
  ```
  ```csharp [C#]
  using JsonEvalRs;

  // Buat instance pertama dan susun logikanya
  var eval1 = new JSONEval(schema);
  var logicId = eval1.CompileLogic("{\"*\": [{\"var\": \"x\"}, 2]}");

  // Gunakan logika yang sama di instance berbeda
  var eval2 = new JSONEval(schema);
  var result = eval2.RunLogic(logicId, "{\"x\": 10}");
  // hasil: 20
  ```
  ```typescript [React Native]
  import { JSONEval } from "@json-eval-rs/react-native";

  // Buat instance pertama dan susun logikanya
  const eval1 = new JSONEval({ schema });
  const logicId = await eval1.compileLogic('{"*": [{"var": "x"}, 2]}');

  // Gunakan logika yang sama di instance berbeda
  const eval2 = new JSONEval({ schema });
  const result = await eval2.runLogic(logicId, { data: '{"x": 10}' });
  // hasil: 20
  ```
  ```typescript [Web / NodeJS]
  import { JSONEval } from "@json-eval-rs/node"; // atau /bundler, /vanilla

  // Buat instance pertama dan susun logikanya
  const eval1 = new JSONEval({ schema });
  const logicId = await eval1.compileLogic('{"*": [{"var": "x"}, 2]}');

  // Gunakan logika yang sama di instance berbeda
  const eval2 = new JSONEval({ schema });
  const result = await eval2.runLogic(logicId, { data: '{"x": 10}' });
  // hasil: 20
  ```
::

### Berbagi Antar-Instance (Cross-Instance Sharing)

```rust
// Susun sekali saja
let logic_id = eval1.compile_logic(logic_str)?;

// Jalankan di berbagai instance dengan data berbeda
let result1 = eval1.run_logic(logic_id, Some(&data1), None)?;
let result2 = eval2.run_logic(logic_id, Some(&data2), None)?;
let result3 = eval3.run_logic(logic_id, Some(&data3), None)?;
```

### Deduplikasi

```rust
// Logika yang sama disusun berkali-kali
let id1 = eval1.compile_logic(r#"{"var": "x"}"#)?;
let id2 = eval2.compile_logic(r#"{"var": "x"}"#)?;

assert_eq!(id1, id2); // Mengembalikan ID yang sama!
```

## Keuntungan

### 1. **Ramah FFI (FFI-Friendly)**
- `CompiledLogicId` hanya berupa `u64` - sangat mudah dikirim antar bahasa pemrograman.
- Tidak perlu proses serialisasi/deserialisasi `CompiledLogic`.
- Bekerja mulus dengan C, C#, JavaScript, dan bahasa lainnya.

### 2. **Efisien Memori**
- Logika terkompilasi disimpan sekali, digunakan berkali-kali.
- Deduplikasi otomatis melalui hashing konten.
- Tidak ada penyimpanan redundan untuk logika yang identik.

### 3. **Aman untuk Multi-thread (Thread-Safe)**
- Global store menggunakan `DashMap` untuk akses konkuren bebas kunci (lock-free).
- Atomic counter untuk pembuatan ID.
- Aman digunakan dari berbagai thread secara bersamaan.

### 4. **Pola Zero-Clone**
- `run_logic` menggunakan referensi ke data.
- Tidak ada kloning yang tidak perlu selama evaluasi.
- Performa optimal untuk evaluasi berulang.

## Referensi API (API Reference)

### Metode JSONEval

```rust
impl JSONEval {
    /// Menyusun logika dan mengembalikan ID global
    pub fn compile_logic(&self, logic_str: &str) -> Result<CompiledLogicId, String>
    
    /// Menjalankan logika yang sudah disusun berdasarkan ID
    pub fn run_logic(
        &mut self, 
        logic_id: CompiledLogicId,
        data: Option<&Value>,
        context: Option<&Value>
    ) -> Result<Value, String>
    
    /// Metode kenyamanan (susun + jalankan dalam satu langkah)
    pub fn compile_and_run_logic(
        &mut self,
        logic_str: &str,
        data: Option<&str>,
        context: Option<&str>
    ) -> Result<Value, String>
}
```

**Parameter:**
- **`logic_str`**: String JSON yang valid mewakili ekspresi JSON Logic (misal: `{"+": [1, 2]}`).
- **`logic_id`**: Handle `CompiledLogicId` yang sangat dioptimalkan yang dikembalikan oleh panggilan `compile_logic` sebelumnya. Aman untuk dibagikan.
- **`data`**: Payload data eksternal opsional untuk diikat ke variabel `{"var": ...}` selama evaluasi.
- **`context`**: Payload konteks opsional yang digunakan untuk resolusi internal atau pengikatan cakupan (scope).

### CompiledLogicId

```rust
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub struct CompiledLogicId(u64);

impl CompiledLogicId {
    pub fn as_u64(&self) -> u64
    pub fn from_u64(id: u64) -> Self
}
```

### Fungsi Global

```rust
/// Menyusun logika dan menyimpan secara global
pub fn compile_logic(logic_json: &str) -> Result<CompiledLogicId, String>

/// Mengambil logika yang sudah disusun berdasarkan ID
pub fn get_compiled_logic(id: CompiledLogicId) -> Option<CompiledLogic>

/// Mengambil statistik penyimpanan (store statistics)
pub fn get_store_stats() -> CompiledLogicStoreStats
```


## Detail Implementasi

### Strategi Penyimpanan (Storage Strategy)

```rust
static COMPILED_LOGIC_STORE: Lazy<CompiledLogicStore> = Lazy::new(|| {
    CompiledLogicStore {
        store: DashMap::new(),           // HashMap aman untuk thread
        next_id: AtomicU64::new(1),      // Counter atomik
    }
});
```

- **Kunci (Key)**: Hash dari string JSON logika (menggunakan `AHasher`)
- **Nilai (Value)**: Tuple `(CompiledLogicId, CompiledLogic)`
- **Pembuatan ID**: Counter atomik sekuensial dimulai dari 1

### Deduplikasi Berbasis Hash

```rust
let mut hasher = AHasher::default();
logic_json.hash(&mut hasher);
let hash = hasher.finish();

// Periksa apakah sudah disusun sebelumnya
if let Some(entry) = store.get(&hash) {
    return Ok(entry.0); // Kembalikan ID yang ada
}
```

### Keamanan Thread (Thread Safety)

- **`DashMap`**: HashMap konkuren bebas kunci (lock-free)
- **`AtomicU64`**: Counter atomik untuk pembuatan ID
- **`Lazy`**: Inisialisasi satu kali dengan keamanan thread

## Karakteristik Performa

### Kompleksitas Waktu (Time Complexity)

- **`compile_logic`**: Rata-rata O(1) (pencarian hash), O(n) jika tidak di-cache (penyusunan)
- **`run_logic`**: Pencarian O(1) + evaluasi O(kompleksitas_logika)
- **Pemeriksaan deduplikasi**: Rata-rata O(1)

### Kompleksitas Ruang (Space Complexity)

- **Per logika unik**: 1 entri di penyimpanan global
- **Overhead ID**: 8 byte (u64)
- **Metadata penyimpanan**: ~40 byte per entri (overhead DashMap)

## Integrasi FFI

### Contoh C/FFI

```c
// Tanda tangan fungsi C
uint64_t json_eval_compile_logic(void* handle, const char* logic_str);
void* json_eval_run_logic(void* handle, uint64_t logic_id, 
                          const char* data, const char* context);
```

### Penggunaan di Bindings

```rust
#[no_mangle]
pub unsafe extern "C" fn json_eval_compile_logic(
    handle: *mut JSONEvalHandle,
    logic_str: *const c_char,
) -> u64 {
    let eval = &(*handle).inner;
    let logic = CStr::from_ptr(logic_str).to_str().unwrap();
    
    match eval.compile_logic(logic) {
        Ok(id) => id.as_u64(),
        Err(_) => 0, // 0 menunjukkan kesalahan
    }
}
```

## Panduan Migrasi (Migration Guide)

### API Lama (Tidak Direkomendasikan untuk FFI)

```rust
let compiled = CompiledLogic::compile(&logic)?;
let result = evaluator.evaluate(&compiled, &data)?;
```

**Masalah**:
- `CompiledLogic` tidak dapat melintasi batasan FFI
- Harus serialisasi/deserialisasi untuk FFI
- Tidak dapat dibagikan antar instance

### API Baru (Direkomendasikan)

```rust
// Rust native
let logic_id = eval.compile_logic(logic_str)?;
let result = eval.run_logic(logic_id, Some(&data), None)?;

// Ramah FFI
uint64_t id = json_eval_compile_logic(handle, logic_str);
result_t res = json_eval_run_logic(handle, id, data, context);
```

**Keuntungan**:
- ID aman untuk FFI (u64)
- Logika disimpan secara global
- Dapat dibagikan antar instance
- Deduplikasi otomatis

## Praktik Terbaik

### 1. Susun Sekali, Jalankan Banyak

```rust
// ✅ Baik - Susun sekali
let logic_id = eval.compile_logic(logic_str)?;

for data in datasets {
    let result = eval.run_logic(logic_id, Some(&data), None)?;
    // Proses hasil...
}
```

```rust
// ❌ Buruk - Susun setiap saat
for data in datasets {
    let result = eval.compile_and_run_logic(logic_str, Some(&data), None)?;
}
```

### 2. Berbagi ID Antar Instance

```rust
// ✅ Baik - Berbagi logika yang sudah disusun
let logic_id = eval1.compile_logic(logic_str)?;

let result1 = eval1.run_logic(logic_id, Some(&data1), None)?;
let result2 = eval2.run_logic(logic_id, Some(&data2), None)?;
```

### 3. Simpan ID untuk Digunakan Kembali

```rust
struct MyApp {
    validation_logic: CompiledLogicId,
    transform_logic: CompiledLogicId,
}

impl MyApp {
    fn new(eval: &JSONEval) -> Result<Self, String> {
        Ok(Self {
            validation_logic: eval.compile_logic(VALIDATION_LOGIC)?,
            transform_logic: eval.compile_logic(TRANSFORM_LOGIC)?,
        })
    }
    
    fn validate(&self, eval: &mut JSONEval, data: &Value) -> Result<bool, String> {
        let result = eval.run_logic(self.validation_logic, Some(data), None)?;
        Ok(result.as_bool().unwrap_or(false))
    }
}
```

## Statistik dan Pemantauan

### Ambil Statistik Penyimpanan

```rust
use json_eval_rs::compiled_logic_store;

let stats = compiled_logic_store::get_store_stats();
println!("Jumlah logika disusun: {}", stats.compiled_count);
println!("ID berikutnya: {}", stats.next_id);
```

### Contoh Output

```
Jumlah logika disusun: 42
ID berikutnya: 43
```

## Pengujian (Testing)

### Unit Tests

```rust
#[test]
fn test_cross_instance_sharing() {
    let schema = json!({"type": "object"}).to_string();
    let data = json!({"x": 10}).to_string();
    
    // Susun dengan instance pertama
    let eval1 = JSONEval::new(&schema, None, Some(&data)).unwrap();
    let logic_id = eval1.compile_logic(r#"{"var": "x"}"#).unwrap();
    
    // Gunakan dengan instance kedua
    let mut eval2 = JSONEval::new(&schema, None, Some(&data)).unwrap();
    let result = eval2.run_logic(logic_id, Some(&json!({"x": 20})), None).unwrap();
    
    assert_eq!(result, json!(20));
}
```

## Batasan (Limitations)

1. **State Global**: Penyimpanan bersifat global dan bertahan selama masa hidup proses.
2. **Tidak Ada Pembersihan Otomatis**: Logika yang disusun tidak pernah dihapus secara otomatis (sengaja untuk performa).
3. **Penggunaan Memori**: Tumbuh seiring dengan ekspresi logika unik yang disusun.
4. **Pencarian Linear untuk ID**: Mendapatkan logika berdasarkan ID memerlukan pencarian linear (dapat dioptimalkan dengan indeks terbalik).

## Perbaikan di Masa Depan

1. **Indeks Terbalik**: Tambahkan map ID → CompiledLogic untuk pencarian O(1).
2. **LRU Eviction**: Cache LRU opsional dengan batas ukuran.
3. **Metrik**: Lacak tingkat hit/miss, waktu penyusunan.
4. **Ekspor/Impor**: Serialisasi penyimpanan ke disk untuk persistensi.
5. **Kompresi**: Kompres logika yang disimpan untuk mengurangi penggunaan memori.

## Log Perubahan (Changelog)

### v0.0.25

- ✅ Implementasi awal global compiled logic store
- ✅ Penambahan tipe `CompiledLogicId`
- ✅ Implementasi deduplikasi berbasis hash
- ✅ Penambahan penyimpanan global aman thread (thread-safe)
- ✅ Pembaruan API `compile_logic` dan `run_logic`
- ✅ Penambahan pengujian komprehensif
- ✅ Siap FFI untuk semua bindings
