use std::rc::Rc;
use std::cell::RefCell;
use std::collections::HashMap;
use serde_json::{json, Value};
use jse::{Engine, Env, Functor, ast::AstError};
fn eval_meta_value(_env: &Rc<RefCell<Env>>, value: &Value) -> Result<Value, AstError> {
Ok(value.clone())
}
fn get_meta(env: &Rc<RefCell<Env>>, _args: &[Value]) -> Result<Value, AstError> {
let meta = env.borrow().get_meta().clone();
let mut result = serde_json::Map::new();
for (k, v) in meta {
let evaluated = eval_meta_value(env, &v)?;
result.insert(k, evaluated);
}
Ok(Value::Object(result))
}
fn get_meta_key(env: &Rc<RefCell<Env>>, args: &[Value]) -> Result<Value, AstError> {
if args.is_empty() {
return Ok(Value::Null);
}
let key = match &args[0] {
Value::String(s) => s.clone(),
_ => return Ok(Value::Null),
};
let meta = env.borrow().get_meta().clone();
if meta.is_empty() {
return Ok(Value::Null);
}
match meta.get(&key) {
Some(value) => eval_meta_value(env, value),
None => Ok(Value::Null),
}
}
fn meta_with_args(env: &Rc<RefCell<Env>>, args: &[Value]) -> Result<Value, AstError> {
let meta = env.borrow().get_meta().clone();
let mut meta_result = serde_json::Map::new();
for (k, v) in meta {
let evaluated = eval_meta_value(env, &v)?;
meta_result.insert(k, evaluated);
}
Ok(json!({
"meta": Value::Object(meta_result),
"args": Value::Array(args.to_vec())
}))
}
thread_local! {
static LAST_META: RefCell<HashMap<String, Value>> = RefCell::new(HashMap::new());
}
fn identity_with_meta(env: &Rc<RefCell<Env>>, args: &[Value]) -> Result<Value, AstError> {
let meta = env.borrow().get_meta().clone();
let mut stored = HashMap::new();
for (k, v) in meta {
let evaluated = eval_meta_value(env, &v)?;
stored.insert(k, evaluated);
}
LAST_META.with(|last_meta| {
*last_meta.borrow_mut() = stored;
});
if !args.is_empty() {
eval_meta_value(env, &args[0])
} else {
Ok(Value::Null)
}
}
fn create_engine_with_meta_functors() -> Engine {
let env = Rc::new(RefCell::new(Env::new()));
let mut functors: HashMap<&'static str, Functor> = HashMap::new();
functors.insert("$get_meta", get_meta);
functors.insert("$get_meta_key", get_meta_key);
functors.insert("$meta_with_args", meta_with_args);
functors.insert("$identity", identity_with_meta);
for (name, functor) in functors {
env.borrow_mut().register_functor(name.to_string(), functor);
}
Engine::new(env)
}
#[test]
fn test_meta_basic_passing() {
let engine = create_engine_with_meta_functors();
let expr = json!({
"$get_meta": null,
"key1": "value1",
"key2": 42
});
let result = engine.execute(&expr).expect("execute error");
let result_map = result.as_object().expect("expected object result");
assert!(result_map.contains_key("key1"), "expected key1 in result");
assert!(result_map.contains_key("key2"), "expected key2 in result");
}
#[test]
fn test_meta_string_value() {
let engine = create_engine_with_meta_functors();
let expr = json!({
"$get_meta_key": "name",
"name": "test_value"
});
let result = engine.execute(&expr).expect("execute error");
assert_eq!(result, json!("test_value"));
}
#[test]
fn test_meta_number_value() {
let engine = create_engine_with_meta_functors();
let expr = json!({
"$get_meta_key": "count",
"count": 123
});
let result = engine.execute(&expr).expect("execute error");
assert_eq!(result, json!(123));
}
#[test]
fn test_meta_multiple_keys() {
let engine = create_engine_with_meta_functors();
let expr = json!({
"$get_meta": null,
"first": "one",
"second": "two",
"third": 3
});
let result = engine.execute(&expr).expect("execute error");
let result_map = result.as_object().expect("expected object result");
assert_eq!(result_map.get("first"), Some(&json!("one")));
assert_eq!(result_map.get("second"), Some(&json!("two")));
assert_eq!(result_map.get("third"), Some(&json!(3)));
}
#[test]
fn test_meta_with_args() {
let engine = create_engine_with_meta_functors();
let expr = json!({
"$meta_with_args": ["arg1", "arg2"],
"meta_key": "meta_value"
});
let result = engine.execute(&expr).expect("execute error");
let result_map = result.as_object().expect("expected object result");
assert!(result_map.contains_key("meta"), "expected 'meta' in result");
assert!(result_map.contains_key("args"), "expected 'args' in result");
let meta = result_map.get("meta").unwrap().as_object().unwrap();
assert_eq!(meta.get("meta_key"), Some(&json!("meta_value")));
}
#[test]
fn test_meta_cleared_after_functor() {
let engine = create_engine_with_meta_functors();
let expr1 = json!({
"$get_meta": null,
"temp_key": "temp_value"
});
let result1 = engine.execute(&expr1).expect("execute error");
let result_map1 = result1.as_object().expect("expected object result");
assert!(result_map1.contains_key("temp_key"), "expected temp_key in first result");
let expr2 = json!({
"$get_meta": null
});
let result2 = engine.execute(&expr2).expect("execute error");
let result_map2 = result2.as_object().expect("expected object result");
assert!(result_map2.is_empty(), "expected empty map, got {:?}", result_map2);
}
#[test]
fn test_meta_available_during_functor_execution() {
let engine = create_engine_with_meta_functors();
LAST_META.with(|m| *m.borrow_mut() = HashMap::new());
let expr = json!({
"$identity": "return_value",
"stored_key": "stored_value"
});
let result = engine.execute(&expr).expect("execute error");
assert_eq!(result, json!("return_value"));
LAST_META.with(|last_meta| {
let meta = last_meta.borrow();
assert!(!meta.is_empty(), "expected lastMeta to be set");
assert_eq!(meta.get("stored_key"), Some(&json!("stored_value")));
});
}
#[test]
fn test_meta_object_value() {
let engine = create_engine_with_meta_functors();
let expr = json!({
"$get_meta_key": "config",
"config": {
"nested": "value",
"number": 42
}
});
let result = engine.execute(&expr).expect("execute error");
let config = result.as_object().expect("expected object");
assert_eq!(config.get("nested"), Some(&json!("value")));
assert_eq!(config.get("number"), Some(&json!(42)));
}
#[test]
fn test_meta_list_value() {
let engine = create_engine_with_meta_functors();
let expr = json!({
"$get_meta_key": "items",
"items": [1, 2, 3]
});
let result = engine.execute(&expr).expect("execute error");
let items = result.as_array().expect("expected array");
assert_eq!(items.len(), 3);
assert_eq!(items[0], json!(1));
assert_eq!(items[1], json!(2));
assert_eq!(items[2], json!(3));
}
#[test]
fn test_meta_null_value() {
let engine = create_engine_with_meta_functors();
let expr = json!({
"$get_meta_key": "nullable",
"nullable": null
});
let result = engine.execute(&expr).expect("execute error");
assert!(result.is_null());
}
#[test]
fn test_meta_boolean_true() {
let engine = create_engine_with_meta_functors();
let expr = json!({
"$get_meta_key": "flag",
"flag": true
});
let result = engine.execute(&expr).expect("execute error");
assert_eq!(result, json!(true));
}
#[test]
fn test_meta_boolean_false() {
let engine = create_engine_with_meta_functors();
let expr = json!({
"$get_meta_key": "flag",
"flag": false
});
let result = engine.execute(&expr).expect("execute error");
assert_eq!(result, json!(false));
}
#[test]
fn test_meta_nested_list_value() {
let engine = create_engine_with_meta_functors();
let expr = json!({
"$get_meta_key": "nested",
"nested": [[1, 2], [3, 4]]
});
let result = engine.execute(&expr).expect("execute error");
let nested = result.as_array().expect("expected array");
assert_eq!(nested.len(), 2);
}
#[test]
fn test_meta_complex_object() {
let engine = create_engine_with_meta_functors();
let expr = json!({
"$get_meta_key": "complex",
"complex": {
"level1": {
"level2": "deep_value"
},
"array": [1, 2, 3]
}
});
let result = engine.execute(&expr).expect("execute error");
let complex = result.as_object().expect("expected object");
let level1 = complex.get("level1").unwrap().as_object().unwrap();
assert_eq!(level1.get("level2"), Some(&json!("deep_value")));
let arr = complex.get("array").unwrap().as_array().unwrap();
assert_eq!(arr.len(), 3);
}
#[test]
fn test_meta_missing_key() {
let engine = create_engine_with_meta_functors();
let expr = json!({
"$get_meta_key": "nonexistent"
});
let result = engine.execute(&expr).expect("execute error");
assert!(result.is_null(), "expected null for missing key, got {:?}", result);
}