Phase 6: Add action_cache and expr_cache to RheiContext + cache-first eval/execute methods
This commit is contained in:
@@ -11,10 +11,18 @@ pub struct RheiContext {
|
||||
engine: Engine,
|
||||
init_ast: AST,
|
||||
scope: RefCell<Scope<'static>>,
|
||||
action_cache: RefCell<HashMap<String, AST>>,
|
||||
expr_cache: RefCell<HashMap<String, AST>>,
|
||||
}
|
||||
|
||||
impl RheiContext {
|
||||
pub fn new(scripts: &[String]) -> Self {
|
||||
let ctx = Self::new_empty(scripts);
|
||||
ctx.precompile_scripts(scripts);
|
||||
ctx
|
||||
}
|
||||
|
||||
fn new_empty(scripts: &[String]) -> Self {
|
||||
let mut engine = Engine::new();
|
||||
|
||||
engine.on_print(|s| println!("[rhei] {s}"));
|
||||
@@ -46,6 +54,8 @@ impl RheiContext {
|
||||
engine,
|
||||
init_ast: combined,
|
||||
scope: RefCell::new(Scope::new()),
|
||||
action_cache: RefCell::new(HashMap::new()),
|
||||
expr_cache: RefCell::new(HashMap::new()),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -86,7 +96,10 @@ impl RheiContext {
|
||||
self.sync_scope(variables);
|
||||
let mut scope = self.scope.borrow_mut();
|
||||
|
||||
match self.engine.eval_expression_with_scope::<Dynamic>(&mut *scope, expr) {
|
||||
let ast = self.get_or_compile_expr(expr);
|
||||
match ast {
|
||||
Some(ast) => {
|
||||
match self.engine.eval_ast_with_scope::<Dynamic>(&mut *scope, &ast) {
|
||||
Ok(val) => dynamic_to_value(&val),
|
||||
Err(e) => {
|
||||
eprintln!("⚠️ Rhei eval_expr error: {e}");
|
||||
@@ -94,12 +107,18 @@ impl RheiContext {
|
||||
}
|
||||
}
|
||||
}
|
||||
None => Value::None,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn eval_condition(&self, expr: &str, variables: &HashMap<String, Value>) -> bool {
|
||||
self.sync_scope(variables);
|
||||
let mut scope = self.scope.borrow_mut();
|
||||
|
||||
match self.engine.eval_expression_with_scope::<bool>(&mut *scope, expr) {
|
||||
let ast = self.get_or_compile_expr(expr);
|
||||
match ast {
|
||||
Some(ast) => {
|
||||
match self.engine.eval_ast_with_scope::<bool>(&mut *scope, &ast) {
|
||||
Ok(b) => b,
|
||||
Err(e) => {
|
||||
eprintln!("⚠️ Rhei eval_condition error: {e}");
|
||||
@@ -107,21 +126,20 @@ impl RheiContext {
|
||||
}
|
||||
}
|
||||
}
|
||||
None => false,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn execute_action(&self, script: &str, variables: &mut HashMap<String, Value>) {
|
||||
self.sync_scope(variables);
|
||||
let mut scope = self.scope.borrow_mut();
|
||||
|
||||
match self.engine.compile(script) {
|
||||
Ok(action_ast) => {
|
||||
let action_ast = self.get_or_compile_action(script);
|
||||
if let Some(action_ast) = action_ast {
|
||||
if let Err(e) = self.engine.run_ast_with_scope(&mut *scope, &action_ast) {
|
||||
eprintln!("⚠️ Rhei action execution error: {e}");
|
||||
}
|
||||
}
|
||||
Err(e) => {
|
||||
eprintln!("⚠️ Rhei action compilation error: {e}");
|
||||
}
|
||||
}
|
||||
|
||||
for (name, _, val) in scope.iter_raw() {
|
||||
let s_val = dynamic_to_value(&val);
|
||||
@@ -130,6 +148,81 @@ impl RheiContext {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn get_or_compile_action(&self, script: &str) -> Option<AST> {
|
||||
let mut cache = self.action_cache.borrow_mut();
|
||||
if let Some(ast) = cache.get(script) {
|
||||
return Some(ast.clone());
|
||||
}
|
||||
match self.engine.compile(script) {
|
||||
Ok(ast) => {
|
||||
cache.insert(script.to_string(), ast.clone());
|
||||
Some(ast)
|
||||
}
|
||||
Err(e) => {
|
||||
eprintln!("⚠️ Rhei action compilation error: {e}");
|
||||
None
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn get_or_compile_expr(&self, expr: &str) -> Option<AST> {
|
||||
let mut cache = self.expr_cache.borrow_mut();
|
||||
if let Some(ast) = cache.get(expr) {
|
||||
return Some(ast.clone());
|
||||
}
|
||||
match self.engine.compile_expression(expr) {
|
||||
Ok(ast) => {
|
||||
cache.insert(expr.to_string(), ast.clone());
|
||||
Some(ast)
|
||||
}
|
||||
Err(e) => {
|
||||
eprintln!("⚠️ Rhei expression compilation error: {e}");
|
||||
None
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn precompile_scripts(&self, scripts: &[String]) {
|
||||
for script in scripts {
|
||||
self.get_or_compile_action(script);
|
||||
}
|
||||
}
|
||||
|
||||
pub fn precompile_actions(&self, actions: &[String]) {
|
||||
for action in actions {
|
||||
self.get_or_compile_action(action);
|
||||
}
|
||||
}
|
||||
|
||||
pub fn precompile_exprs(&self, exprs: &[String]) {
|
||||
for expr in exprs {
|
||||
self.get_or_compile_expr(expr);
|
||||
}
|
||||
}
|
||||
|
||||
pub fn precompile_all_from_doc(&self, doc: &super::Document) {
|
||||
for script in &doc.rhei_scripts {
|
||||
self.get_or_compile_action(script);
|
||||
}
|
||||
for root in &doc.roots {
|
||||
Self::collect_and_precompile(root, self);
|
||||
}
|
||||
}
|
||||
|
||||
fn collect_and_precompile(el: &super::Element, ctx: &RheiContext) {
|
||||
for (k, v) in &el.properties {
|
||||
if k.starts_with("__on:") && !v.is_empty() {
|
||||
ctx.get_or_compile_action(v);
|
||||
}
|
||||
if let Some(expr) = v.strip_prefix(RHEI_PREFIX) {
|
||||
ctx.get_or_compile_expr(expr);
|
||||
}
|
||||
}
|
||||
for child in &el.children {
|
||||
Self::collect_and_precompile(child, ctx);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Default for RheiContext {
|
||||
@@ -143,7 +236,7 @@ pub fn value_to_dynamic(v: &Value) -> Dynamic {
|
||||
Value::Int(i) => Dynamic::from(*i),
|
||||
Value::Float(f) => Dynamic::from(*f),
|
||||
Value::Bool(b) => Dynamic::from(*b),
|
||||
Value::Str(s) => Dynamic::from(s.to_string()),
|
||||
Value::Str(s) => str_to_dynamic(s),
|
||||
Value::None => Dynamic::UNIT,
|
||||
Value::Array(arr) => {
|
||||
let d: rhai::Dynamic = arr.iter().map(value_to_dynamic).collect();
|
||||
@@ -152,6 +245,13 @@ pub fn value_to_dynamic(v: &Value) -> Dynamic {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn str_to_dynamic(s: &str) -> Dynamic {
|
||||
if let Ok(i) = s.parse::<i64>() { return Dynamic::from(i); }
|
||||
if let Ok(f) = s.parse::<f64>() { return Dynamic::from(f); }
|
||||
if let Ok(b) = s.parse::<bool>() { return Dynamic::from(b); }
|
||||
Dynamic::from(s.to_owned())
|
||||
}
|
||||
|
||||
pub fn dynamic_to_value(d: &Dynamic) -> Value {
|
||||
if d.is_string() {
|
||||
return Value::Str(CompactString::new(d.clone().into_string().unwrap_or_default()));
|
||||
|
||||
Reference in New Issue
Block a user