aether/engine/
global.rs

1//! 全局单例引擎模式
2//!
3//! 使用线程局部存储(thread_local)创建引擎单例,适合单线程高频调用场景。
4//! 每次执行前清空环境变量以保证隔离性,但保留AST缓存以优化性能。
5//!
6//! **注意**:由于使用 thread_local,每个线程有独立的引擎实例。
7//! 如需多线程共享引擎池,请使用 `EnginePool`。
8
9use crate::{Aether, Value};
10use std::cell::RefCell;
11
12thread_local! {
13    /// 线程局部 Aether 引擎单例
14    ///
15    /// **线程安全**:每个线程有独立的引擎实例
16    ///
17    /// **性能优化**:
18    /// - 每个线程只创建一次引擎实例
19    /// - AST 缓存在多次调用间累积(可达142x加速)
20    /// - 内置函数注册表复用
21    static THREAD_LOCAL_AETHER: RefCell<Aether> = RefCell::new(Aether::new());
22}
23
24/// 全局单例引擎
25///
26/// # 使用场景
27///
28/// - ✅ 单线程应用
29/// - ✅ 高频率DSL执行(如配置解析、规则引擎)
30/// - ✅ 需要最大化性能
31/// - ❌ 多线程并发(会有锁竞争,请使用 EnginePool)
32///
33/// # 隔离性保证
34///
35/// - 每次 `eval_isolated()` 前清空环境变量
36/// - 不同执行间的变量不会互相影响
37/// - AST缓存跨执行保留(性能优化)
38///
39/// # 示例
40///
41/// ```rust
42/// use aether::engine::GlobalEngine;
43///
44/// // 执行代码(隔离环境)
45/// let result = GlobalEngine::eval_isolated("Set X 10\n(X + 20)").unwrap();
46/// assert_eq!(result.to_string(), "30");
47///
48/// // 再次执行(上次的X不存在,环境已清空)
49/// let result2 = GlobalEngine::eval_isolated("(X + 1)"); // 错误:X未定义
50/// assert!(result2.is_err());
51///
52/// // 如果需要保留变量(不隔离),使用 eval()
53/// GlobalEngine::eval("Set Y 100").unwrap();
54/// let result3 = GlobalEngine::eval("(Y + 1)").unwrap();
55/// assert_eq!(result3.to_string(), "101");
56/// ```
57///
58/// # 性能提示
59///
60/// 对于重复执行相同代码的场景,性能提升显著:
61///
62/// ```rust
63/// use aether::engine::GlobalEngine;
64///
65/// let code = "Set X 10\n(X * 2)";
66///
67/// // 第一次:解析 + 缓存 + 执行
68/// GlobalEngine::eval_isolated(code).unwrap();
69///
70/// // 后续执行:直接从缓存读取AST(142x faster!)
71/// for _ in 0..1000 {
72///     GlobalEngine::eval_isolated(code).unwrap();
73/// }
74/// ```
75pub struct GlobalEngine;
76
77impl GlobalEngine {
78    /// 使用全局引擎执行代码(隔离环境)
79    ///
80    /// 每次执行前清空环境变量,确保不同执行间的隔离性。
81    /// AST缓存保留,性能最优。
82    ///
83    /// # 参数
84    ///
85    /// - `code`: 要执行的Aether代码
86    ///
87    /// # 返回
88    ///
89    /// - `Ok(Value)`: 执行结果
90    /// - `Err(String)`: 错误信息
91    ///
92    /// # 线程安全
93    ///
94    /// 每个线程有独立的引擎实例,无需担心线程安全问题。
95    pub fn eval_isolated(code: &str) -> Result<Value, String> {
96        THREAD_LOCAL_AETHER.with(|engine| {
97            let mut engine = engine.borrow_mut();
98
99            // 重置环境(保证隔离性)
100            engine.evaluator.reset_env();
101
102            // 执行代码(使用缓存)
103            engine.eval(code)
104        })
105    }
106
107    /// 使用全局引擎执行代码(非隔离,变量会累积)
108    ///
109    /// **警告**:此方法不会清空环境,变量会在多次调用间保留。
110    /// 仅在明确需要变量累积时使用。
111    ///
112    /// # 示例
113    ///
114    /// ```rust
115    /// use aether::engine::GlobalEngine;
116    ///
117    /// // 第一次设置变量
118    /// GlobalEngine::eval("Set X 10").unwrap();
119    ///
120    /// // 第二次可以使用X(变量保留)
121    /// let result = GlobalEngine::eval("(X + 20)").unwrap();
122    /// assert_eq!(result.to_string(), "30");
123    ///
124    /// // 记得清空(如果不再需要)
125    /// GlobalEngine::clear_env();
126    /// ```
127    pub fn eval(code: &str) -> Result<Value, String> {
128        THREAD_LOCAL_AETHER.with(|engine| engine.borrow_mut().eval(code))
129    }
130
131    /// 清空全局引擎的环境变量
132    ///
133    /// 用于手动清理 `eval()` 累积的变量。
134    /// `eval_isolated()` 会自动清空,无需调用此方法。
135    pub fn clear_env() {
136        THREAD_LOCAL_AETHER.with(|engine| {
137            engine.borrow_mut().evaluator.reset_env();
138        });
139    }
140
141    /// 清空全局引擎的AST缓存
142    ///
143    /// 如果执行了大量不同的代码,缓存可能占用内存。
144    /// 定期清理可以释放内存。
145    ///
146    /// **注意**:清理后性能会下降,直到缓存重新建立。
147    pub fn clear_cache() {
148        THREAD_LOCAL_AETHER.with(|engine| {
149            engine.borrow_mut().clear_cache();
150        });
151    }
152
153    /// 获取AST缓存统计信息
154    ///
155    /// 返回缓存命中率、命中次数、未命中次数等信息。
156    pub fn cache_stats() -> Option<crate::cache::CacheStats> {
157        THREAD_LOCAL_AETHER.with(|engine| Some(engine.borrow().cache_stats()))
158    }
159
160    /// 配置优化选项
161    ///
162    /// # 参数
163    ///
164    /// - `constant_folding`: 常量折叠优化
165    /// - `dead_code`: 死代码消除
166    /// - `tail_recursion`: 尾递归优化
167    pub fn set_optimization(constant_folding: bool, dead_code: bool, tail_recursion: bool) {
168        THREAD_LOCAL_AETHER.with(|engine| {
169            engine
170                .borrow_mut()
171                .set_optimization(constant_folding, dead_code, tail_recursion);
172        });
173    }
174
175    /// 使用全局引擎异步执行代码(隔离环境)
176    ///
177    /// 异步版本的 `eval_isolated()`,适合在 async/await 应用中使用。
178    ///
179    /// # 示例
180    ///
181    /// ```no_run
182    /// use aether::engine::GlobalEngine;
183    ///
184    /// #[tokio::main]
185    /// async fn main() {
186    ///     let result = GlobalEngine::eval_isolated_async("Set X 10\n(X + 20)").await.unwrap();
187    ///     println!("Result: {}", result);
188    /// }
189    /// ```
190    #[cfg(feature = "async")]
191    pub async fn eval_isolated_async(code: &str) -> Result<Value, String> {
192        tokio::task::yield_now().await;
193        Self::eval_isolated(code)
194    }
195
196    /// 使用全局引擎异步执行代码(非隔离)
197    ///
198    /// 异步版本的 `eval()`,变量会在多次调用间保留。
199    #[cfg(feature = "async")]
200    pub async fn eval_async(code: &str) -> Result<Value, String> {
201        tokio::task::yield_now().await;
202        Self::eval(code)
203    }
204}
205
206#[cfg(test)]
207mod tests {
208    use super::*;
209
210    #[test]
211    fn test_global_engine_isolated() {
212        // 第一次执行
213        let result = GlobalEngine::eval_isolated("Set X 10\n(X + 20)").unwrap();
214        assert_eq!(result.to_string(), "30");
215
216        // 第二次执行,X应该不存在(环境已清空)
217        let result = GlobalEngine::eval_isolated("X");
218        assert!(result.is_err());
219    }
220
221    #[test]
222    fn test_global_engine_non_isolated() {
223        // 清空环境
224        GlobalEngine::clear_env();
225
226        // 设置变量
227        GlobalEngine::eval("Set Y 100").unwrap();
228
229        // 变量应该保留
230        let result = GlobalEngine::eval("(Y + 1)").unwrap();
231        assert_eq!(result.to_string(), "101");
232
233        // 清空
234        GlobalEngine::clear_env();
235    }
236
237    #[test]
238    fn test_global_engine_cache() {
239        let code = "Set X 10\n(X * 2)";
240
241        // 第一次执行
242        GlobalEngine::eval_isolated(code).unwrap();
243
244        // 获取缓存统计
245        let stats = GlobalEngine::cache_stats().unwrap();
246        assert!(stats.hits + stats.misses > 0);
247    }
248}