1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
//! JS Engine implemented by [QuickJs](https://crates.io/crates/quick-js).

use crate::{
    error::{Error, Result},
    js_engine::{JsEngine, JsScope, JsValue},
};
use core::convert::TryInto;

/// QuickJS Engine.
pub struct Engine(quick_js::Context);

impl JsEngine for Engine {
    fn new() -> Result<Self> {
        Ok(Self(quick_js::Context::new()?))
    }
}

/// QuickJS Scope.
pub struct Scope<'a>(&'a quick_js::Context);

impl<'a> JsScope<'a> for Scope<'a> {
    type JsEngine = Engine;
    type JsValue = Value;

    fn global_scope(engine: &'a mut Self::JsEngine) -> Self {
        Self(&engine.0)
    }

    fn eval(&'a self, code: &str) -> Result<Self::JsValue> {
        Ok(Value(self.0.eval(code)?))
    }

    fn call_function(
        &'a self,
        func_name: &str,
        args: impl Iterator<Item = Self::JsValue>,
    ) -> Result<Self::JsValue> {
        Ok(Value(self.0.call_function(func_name, args.map(|v| v.0))?))
    }

    fn create_bool_value(&'a self, input: bool) -> Result<Self::JsValue> {
        Ok(Value(quick_js::JsValue::Bool(input)))
    }

    fn create_int_value(&'a self, input: i32) -> Result<Self::JsValue> {
        Ok(Value(quick_js::JsValue::Int(input)))
    }

    fn create_float_value(&'a self, input: f64) -> Result<Self::JsValue> {
        Ok(Value(quick_js::JsValue::Float(input)))
    }

    fn create_string_value(&'a self, input: String) -> Result<Self::JsValue> {
        Ok(Value(quick_js::JsValue::String(input)))
    }

    fn create_object_value(
        &'a self,
        input: impl Iterator<Item = (String, Self::JsValue)>,
    ) -> Result<Self::JsValue> {
        let obj = input.into_iter().map(|(k, v)| (k, v.0)).collect();
        Ok(Value(quick_js::JsValue::Object(obj)))
    }
}

/// QuickJS Value.
#[derive(Debug)]
pub struct Value(quick_js::JsValue);

impl JsValue for Value {
    fn into_string(self) -> Result<String> {
        Ok(self.0.try_into()?)
    }
}

impl From<quick_js::ContextError> for Error {
    fn from(e: quick_js::ContextError) -> Self {
        Self::JsInitError(format!("{}", e))
    }
}

impl From<quick_js::ExecutionError> for Error {
    fn from(e: quick_js::ExecutionError) -> Self {
        Self::JsExecError(format!("{}", e))
    }
}

impl From<quick_js::ValueError> for Error {
    fn from(e: quick_js::ValueError) -> Self {
        Self::JsValueError(format!("{}", e))
    }
}