Skip to main content

rexpr/
runtime.rs

1use crate::ast::Node;
2use crate::cache::RWLockMapCache;
3use crate::lexer::lexer;
4use crate::parser::parse;
5use crate::token::TokenMap;
6use dashmap::DashMap;
7use serde_json::Value;
8
9/// the express engine for  exe code on runtime
10#[derive(Debug)]
11pub struct RExprRuntime {
12    pub expr_cache: DashMap<String, Node>,
13    pub token_map: TokenMap<'static>,
14}
15
16impl RExprRuntime {
17    pub fn new() -> Self {
18        return Self {
19            expr_cache: DashMap::new(),
20            token_map: TokenMap::new(),
21        };
22    }
23
24    ///eval express with arg value,if cache have value it will no run lexer expr.
25    pub fn eval(&self, expr: &str, arg: &Value) -> Result<Value, crate::error::Error> {
26        match self.expr_cache.get(expr) {
27            Some(v) => {
28                return v.eval(arg);
29            }
30            _ => {
31                let node = self.parse(expr)?;
32                self.expr_cache.insert(expr.to_string(), node.clone());
33                return node.eval(arg);
34            }
35        }
36    }
37
38    /// no cache mode to run engine
39    pub fn eval_no_cache(
40        &self,
41        lexer_arg: &str,
42        arg: &Value,
43    ) -> Result<Value, crate::error::Error> {
44        let tokens = lexer(lexer_arg, &self.token_map)?;
45        let node = parse(&self.token_map, &tokens, lexer_arg)?;
46        return node.eval(arg);
47    }
48
49    /// parse get node
50    pub fn parse(&self, lexer_arg: &str) -> Result<Node, crate::error::Error> {
51        let tokens = lexer(lexer_arg, &self.token_map)?;
52        let node = parse(&self.token_map, &tokens, lexer_arg)?;
53        return Ok(node);
54    }
55}
56
57#[cfg(test)]
58mod test {
59    use crate::bencher::QPS;
60    use crate::runtime::RExprRuntime;
61    use std::sync::Arc;
62    use std::thread::{sleep, spawn};
63    use std::time::Duration;
64
65    //cargo test --release --package rexpr --lib runtime::test::test_bench --no-fail-fast -- --exact -Z unstable-options --show-output
66    #[test]
67    fn test_bench() {
68        let runtime = RExprRuntime::new();
69        runtime.eval("1+1", &serde_json::Value::Null);
70        runtime.eval("1+1", &serde_json::Value::Null);
71
72        let total = 1000000;
73        let now = std::time::Instant::now();
74        for _ in 0..total {
75            //(Windows10 6Core16GBMem) use Time: 84.0079ms ,each:84 ns/op use QPS: 11900823 QPS/s
76            let r = runtime.eval("1+1", &serde_json::Value::Null).unwrap(); //use Time: 1.5752844s ,each:1575 ns/op use QPS: 634793 QPS/s
77                                                                            //println!("{}",r);
78        }
79        now.time(total);
80        now.qps(total);
81    }
82
83    #[test]
84    fn test_thread_race() {
85        let runtime = Arc::new(RExprRuntime::new());
86        let r1 = runtime.clone();
87        spawn(move || {
88            let total = 1000000;
89            for _ in 0..total {
90                let r = r1.eval("1+1", &serde_json::Value::Null).unwrap();
91            }
92        });
93        let r2 = runtime.clone();
94        spawn(move || {
95            let total = 1000000;
96            for _ in 0..total {
97                let r = r2.eval("1+1", &serde_json::Value::Null).unwrap();
98            }
99        });
100        sleep(Duration::from_secs(10));
101    }
102}