json_eval_rs/rlogic/
mod.rs

1//! RLogic - High-performance JSON Logic compiler and evaluator
2//! 
3//! This module provides a complete implementation of JSON Logic with:
4//! - Pre-compilation of logic expressions for fast repeated evaluation
5//! - Mutation tracking via proxy-like data wrapper (EvalData)
6//! - All data mutations gated through EvalData for safety
7//! - Zero external dependencies (uses only standard library and serde_json)
8//! - Global compiled logic storage for cross-instance sharing
9
10pub mod compiled;
11pub mod evaluator;
12pub mod config;
13pub mod compiled_logic_store;
14
15use serde_json::Value;
16
17pub use compiled::{CompiledLogic, CompiledLogicStore, LogicId};
18pub use evaluator::Evaluator;
19pub use config::RLogicConfig;
20pub use compiled_logic_store::{CompiledLogicId, CompiledLogicStoreStats};
21
22/// Main RLogic engine combining compilation and evaluation
23pub struct RLogic {
24    store: CompiledLogicStore,
25    evaluator: Evaluator,
26}
27
28impl RLogic {
29    /// Create a new RLogic instance with default configuration
30    pub fn new() -> Self {
31        Self::with_config(RLogicConfig::default())
32    }
33    
34    /// Create a new RLogic instance with custom configuration
35    pub fn with_config(config: RLogicConfig) -> Self {
36        Self {
37            store: CompiledLogicStore::new(),
38            evaluator: Evaluator::new().with_config(config),
39        }
40    }
41    
42    /// Compile a JSON Logic expression
43    pub fn compile(&mut self, logic: &Value) -> Result<LogicId, String> {
44        self.store.compile(logic)
45    }
46    
47    /// Evaluate a compiled logic expression against data
48    pub fn run(&self, logic_id: &LogicId, data: &Value) -> Result<Value, String> {
49        let logic = self.store.get(logic_id)
50            .ok_or_else(|| "Logic ID not found".to_string())?;
51        
52        self.evaluator.evaluate(logic, data)
53    }
54    
55    /// Evaluate a compiled logic expression with internal context
56    /// 
57    /// # Arguments
58    /// * `logic_id` - The compiled logic ID
59    /// * `user_data` - User's data (primary lookup source)
60    /// * `internal_context` - Internal variables (e.g., $iteration, $threshold, column vars)
61    /// 
62    /// Variables are resolved in order: internal_context → user_data
63    pub fn run_with_context(
64        &self,
65        logic_id: &LogicId,
66        user_data: &Value,
67        internal_context: &Value,
68    ) -> Result<Value, String> {
69        let logic = self.store.get(logic_id)
70            .ok_or_else(|| "Logic ID not found".to_string())?;
71        
72        self.evaluator.evaluate_with_internal_context(logic, user_data, internal_context)
73    }
74    
75    /// Evaluate a compiled logic expression with custom config
76    pub fn run_with_config(
77        &self,
78        logic_id: &LogicId,
79        data: &Value,
80        config: &RLogicConfig,
81    ) -> Result<Value, String> {
82        let logic = self.store.get(logic_id)
83            .ok_or_else(|| "Logic ID not found".to_string())?;
84        
85        let evaluator = Evaluator::new().with_config(*config);
86        evaluator.evaluate(logic, data)
87    }
88    
89    /// Compile and evaluate a logic expression directly
90    pub fn evaluate(&self, logic: &Value, data: &Value) -> Result<Value, String> {
91        let compiled = CompiledLogic::compile(logic)?;
92        self.evaluator.evaluate(&compiled, data)
93    }
94    
95    /// Get the referenced variables in a compiled logic
96    pub fn get_referenced_vars(&self, logic_id: &LogicId) -> Option<Vec<String>> {
97        self.store.get(logic_id).map(|logic| logic.referenced_vars())
98    }
99    
100    /// Check if a compiled logic has forward references (e.g., references future iterations)
101    pub fn has_forward_reference(&self, logic_id: &LogicId) -> bool {
102        self.store.get(logic_id)
103            .map(|logic| logic.has_forward_reference())
104            .unwrap_or(false)
105    }
106}
107
108impl Default for RLogic {
109    fn default() -> Self {
110        Self::new()
111    }
112}