use crate::{Aether, Value};
use std::cell::RefCell;
thread_local! {
static THREAD_LOCAL_AETHER: RefCell<Aether> = RefCell::new(Aether::new());
}
pub struct GlobalEngine;
impl GlobalEngine {
pub fn eval_isolated(code: &str) -> Result<Value, String> {
THREAD_LOCAL_AETHER.with(|engine| {
let mut engine = engine.borrow_mut();
engine.evaluator.reset_env();
engine.eval(code)
})
}
pub fn eval(code: &str) -> Result<Value, String> {
THREAD_LOCAL_AETHER.with(|engine| engine.borrow_mut().eval(code))
}
pub fn clear_env() {
THREAD_LOCAL_AETHER.with(|engine| {
engine.borrow_mut().evaluator.reset_env();
});
}
pub fn clear_cache() {
THREAD_LOCAL_AETHER.with(|engine| {
engine.borrow_mut().clear_cache();
});
}
pub fn cache_stats() -> Option<crate::cache::CacheStats> {
THREAD_LOCAL_AETHER.with(|engine| Some(engine.borrow().cache_stats()))
}
pub fn set_optimization(constant_folding: bool, dead_code: bool, tail_recursion: bool) {
THREAD_LOCAL_AETHER.with(|engine| {
engine
.borrow_mut()
.set_optimization(constant_folding, dead_code, tail_recursion);
});
}
#[cfg(feature = "async")]
pub async fn eval_isolated_async(code: &str) -> Result<Value, String> {
tokio::task::yield_now().await;
Self::eval_isolated(code)
}
#[cfg(feature = "async")]
pub async fn eval_async(code: &str) -> Result<Value, String> {
tokio::task::yield_now().await;
Self::eval(code)
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_global_engine_isolated() {
let result = GlobalEngine::eval_isolated("Set X 10\n(X + 20)").unwrap();
assert_eq!(result.to_string(), "30");
let result = GlobalEngine::eval_isolated("X");
assert!(result.is_err());
}
#[test]
fn test_global_engine_non_isolated() {
GlobalEngine::clear_env();
GlobalEngine::eval("Set Y 100").unwrap();
let result = GlobalEngine::eval("(Y + 1)").unwrap();
assert_eq!(result.to_string(), "101");
GlobalEngine::clear_env();
}
#[test]
fn test_global_engine_cache() {
let code = "Set X 10\n(X * 2)";
GlobalEngine::eval_isolated(code).unwrap();
let stats = GlobalEngine::cache_stats().unwrap();
assert!(stats.hits + stats.misses > 0);
}
}