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}