use crate::ast::Node;
use crate::cache::RWLockMapCache;
use crate::lexer::lexer;
use crate::parser::parse;
use crate::token::TokenMap;
use dashmap::DashMap;
use serde_json::Value;
#[derive(Debug)]
pub struct RExprRuntime {
pub expr_cache: DashMap<String, Node>,
pub token_map: TokenMap<'static>,
}
impl RExprRuntime {
pub fn new() -> Self {
return Self {
expr_cache: DashMap::new(),
token_map: TokenMap::new(),
};
}
pub fn eval(&self, expr: &str, arg: &Value) -> Result<Value, crate::error::Error> {
match self.expr_cache.get(expr) {
Some(v) => {
return v.eval(arg);
}
_ => {
let node = self.parse(expr)?;
self.expr_cache.insert(expr.to_string(), node.clone());
return node.eval(arg);
}
}
}
pub fn eval_no_cache(
&self,
lexer_arg: &str,
arg: &Value,
) -> Result<Value, crate::error::Error> {
let tokens = lexer(lexer_arg, &self.token_map)?;
let node = parse(&self.token_map, &tokens, lexer_arg)?;
return node.eval(arg);
}
pub fn parse(&self, lexer_arg: &str) -> Result<Node, crate::error::Error> {
let tokens = lexer(lexer_arg, &self.token_map)?;
let node = parse(&self.token_map, &tokens, lexer_arg)?;
return Ok(node);
}
}
#[cfg(test)]
mod test {
use crate::bencher::QPS;
use crate::runtime::RExprRuntime;
use std::sync::Arc;
use std::thread::{sleep, spawn};
use std::time::Duration;
#[test]
fn test_bench() {
let runtime = RExprRuntime::new();
runtime.eval("1+1", &serde_json::Value::Null);
runtime.eval("1+1", &serde_json::Value::Null);
let total = 1000000;
let now = std::time::Instant::now();
for _ in 0..total {
let r = runtime.eval("1+1", &serde_json::Value::Null).unwrap(); }
now.time(total);
now.qps(total);
}
#[test]
fn test_thread_race() {
let runtime = Arc::new(RExprRuntime::new());
let r1 = runtime.clone();
spawn(move || {
let total = 1000000;
for _ in 0..total {
let r = r1.eval("1+1", &serde_json::Value::Null).unwrap();
}
});
let r2 = runtime.clone();
spawn(move || {
let total = 1000000;
for _ in 0..total {
let r = r2.eval("1+1", &serde_json::Value::Null).unwrap();
}
});
sleep(Duration::from_secs(10));
}
}