use super::ScriptingBackend;
use crate::core::{Error, Result, Value};
use rhai::{Engine, Scope};
pub struct RhaiBackend {
engine: Engine,
}
impl RhaiBackend {
pub fn new() -> Self {
let mut engine = Engine::new();
engine.register_fn("to_int", |v: i64| v);
engine.register_fn("to_float", |v: f64| v);
engine.register_fn("to_string", |v: String| v);
Self { engine }
}
}
impl Default for RhaiBackend {
fn default() -> Self {
Self::new()
}
}
impl ScriptingBackend for RhaiBackend {
fn name(&self) -> &'static str {
"rhai"
}
fn supported_languages(&self) -> &[&'static str] {
&["rhai"]
}
fn execute(&self, code: &str, args: &[Value], param_names: &[&str]) -> Result<Value> {
let mut scope = Scope::new();
let mut args_array = rhai::Array::new();
for arg in args {
match arg {
Value::Integer(i) => args_array.push(rhai::Dynamic::from(*i)),
Value::Float(f) => args_array.push(rhai::Dynamic::from(*f)),
Value::Text(s) => args_array.push(rhai::Dynamic::from(s.as_ref().to_string())),
Value::Boolean(b) => args_array.push(rhai::Dynamic::from(*b)),
_ => return Err(Error::internal("Unsupported argument type for Rhai")),
};
}
scope.push("arguments", args_array);
for (i, arg) in args.iter().enumerate() {
let var_name = param_names[i];
match arg {
Value::Integer(i) => scope.push(var_name, *i),
Value::Float(f) => scope.push(var_name, *f),
Value::Text(s) => scope.push(var_name, s.as_ref().to_string()),
Value::Boolean(b) => scope.push(var_name, *b),
_ => return Err(Error::internal("Unsupported argument type for Rhai")),
};
}
match self
.engine
.eval_with_scope::<rhai::Dynamic>(&mut scope, code)
{
Ok(result) => {
if result.is::<i64>() {
Ok(Value::Integer(result.cast::<i64>()))
} else if result.is::<f64>() {
Ok(Value::Float(result.cast::<f64>()))
} else if result.is::<String>() {
Ok(Value::Text(result.cast::<String>().into()))
} else if result.is::<bool>() {
Ok(Value::Boolean(result.cast::<bool>()))
} else {
Err(Error::internal("Unsupported return type from Rhai script"))
}
}
Err(e) => Err(Error::internal(format!("Rhai execution error: {}", e))),
}
}
fn validate_code(&self, code: &str) -> Result<()> {
match self.engine.compile(code) {
Ok(_) => Ok(()),
Err(e) => Err(Error::internal(format!("Rhai syntax error: {}", e))),
}
}
}