use std::collections::HashMap; use std::mem; use std::slice; use std::str; use cel::{Context, Program, Value}; use serde_json; #[unsafe(no_mangle)] pub extern "C" fn allocation(n: usize) -> *mut u8 { mem::ManuallyDrop::new(Vec::with_capacity(n)).as_mut_ptr() } #[unsafe(no_mangle)] pub unsafe extern "C" fn evaluate(s: *const u8) -> *mut u8 { unsafe { let length = u32::from_le_bytes(*(s as *const [u8; 4])) as usize; let input = slice::from_raw_parts(s.offset(4), length); let output = evaluate_buffers(input); mem::ManuallyDrop::new(output).as_mut_ptr() } } fn evaluate_buffers(input: &[u8]) -> Vec { let contents = str::from_utf8(input).unwrap(); let result = evaluate_cel_with_context(contents); let success = result.is_ok(); let message = result.unwrap_or_else(|e| e); let len = message.len(); let mut buffer = Vec::with_capacity(len + 8); buffer.push(if success { 1 } else { 0 }); buffer.extend(vec![0; 3]); buffer.extend_from_slice(&(len as u32).to_le_bytes()); buffer.extend_from_slice(message.as_bytes()); buffer } fn json_to_cel_value(json_value: &serde_json::Value) -> Value { match json_value { serde_json::Value::Null => Value::Null, serde_json::Value::Bool(b) => Value::Bool(*b), serde_json::Value::Number(n) => { if let Some(i) = n.as_i64() { Value::Int(i) } else if let Some(f) = n.as_f64() { Value::Float(f) } else { Value::Null } } serde_json::Value::String(s) => Value::String(s.clone().into()), serde_json::Value::Array(arr) => { let cel_vec: Vec = arr.iter().map(json_to_cel_value).collect(); Value::List(cel_vec.into()) } serde_json::Value::Object(obj) => { let mut cel_map = HashMap::new(); for (key, value) in obj.iter() { cel_map.insert(key.clone(), json_to_cel_value(value)); } Value::Map(cel_map.into()) } } } fn evaluate_cel_with_context(content: &str) -> Result { // Split the input to get expression and context let parts: Vec<&str> = content.split("\n---CONTEXT---\n").collect(); let expression = parts[0].trim(); let context_json = if parts.len() > 1 { parts[1].trim() } else { "{}" }; // Parse the CEL expression let program = match Program::compile(expression) { Ok(prog) => prog, Err(e) => return Err(format!("Compilation error: {}", e)), }; // Create context and add JSON values let mut context = Context::default(); // Parse JSON context if provided and not empty if !context_json.is_empty() && context_json != "{}" { match serde_json::from_str::(context_json) { Ok(json_value) => { if let serde_json::Value::Object(obj) = json_value { for (key, value) in obj.iter() { let cel_value = json_to_cel_value(value); context .add_variable(key, cel_value) .map_err(|e| format!("Context error: {}", e))?; } } else { return Err("JSON context must be an object".to_string()); } } Err(e) => return Err(format!("JSON parsing error: {}", e)), } } // Execute the program match program.execute(&context) { Ok(value) => Ok(format!("{:?}", value)), Err(e) => Err(format!("Execution error: {}", e)), } }