1use std::sync::Arc;
17
18use parking_lot::Mutex;
19use serde_json::Value;
20
21use crate::eval::methods::MethodRegistry;
22use crate::vm::{PassConfig, VM};
23use crate::{Error, Result};
24
25pub struct Engine {
32 vm: Mutex<VM>,
33}
34
35impl Engine {
36 pub fn new() -> Arc<Self> {
37 Arc::new(Self { vm: Mutex::new(VM::new()) })
38 }
39
40 pub fn with_capacity(compile_cap: usize, path_cap: usize) -> Arc<Self> {
41 Arc::new(Self { vm: Mutex::new(VM::with_capacity(compile_cap, path_cap)) })
42 }
43
44 pub fn with_methods(registry: Arc<MethodRegistry>) -> Arc<Self> {
45 Arc::new(Self { vm: Mutex::new(VM::with_registry(registry)) })
46 }
47
48 pub fn run(&self, expr: &str, doc: &Value) -> Result<Value> {
50 self.vm.lock().run_str(expr, doc).map_err(Error::from)
51 }
52
53 pub fn register(
54 &self,
55 name: impl Into<String>,
56 method: impl crate::eval::methods::Method + 'static,
57 ) {
58 self.vm.lock().register(name, method);
59 }
60
61 pub fn set_pass_config(&self, config: PassConfig) {
62 self.vm.lock().set_pass_config(config);
63 }
64
65 pub fn pass_config(&self) -> PassConfig {
66 self.vm.lock().pass_config()
67 }
68}
69
70#[cfg(test)]
73mod tests {
74 use super::*;
75 use serde_json::json;
76
77 #[test]
78 fn engine_runs_and_caches() {
79 let e = Engine::new();
80 let doc = json!({"x": [1, 2, 3, 4]});
81 assert_eq!(e.run("$.x.len()", &doc).unwrap(), json!(4));
82 assert_eq!(e.run("$.x.len()", &doc).unwrap(), json!(4));
84 }
85
86 #[test]
87 fn engine_is_shareable() {
88 let e = Engine::new();
89 let e2 = Arc::clone(&e);
90 let h = std::thread::spawn(move || {
91 let doc = json!({"n": 5});
92 e2.run("$.n", &doc).unwrap()
93 });
94 assert_eq!(h.join().unwrap(), json!(5));
95 }
96}