pmse_v8/
lib.rs

1//! pmse-v8
2#![deny(unsafe_code)]
3
4use std::error::Error;
5
6// re-export
7pub use v8;
8
9use v8::{
10    Context, ContextScope, CreateParams, HandleScope, Isolate, Local, OwnedIsolate, Script, Value,
11    V8,
12};
13
14mod err;
15
16pub use err::E;
17
18/// 注意: 只能调用一次
19fn 初始化_v8() {
20    let 平台 = v8::new_default_platform(0, false).make_shared();
21    V8::initialize_platform(平台);
22    V8::initialize();
23}
24
25/// 创建 v8 实例 (Isolate)
26fn 创建实例() -> OwnedIsolate {
27    Isolate::new(CreateParams::default())
28}
29
30/// 编译 JS 代码字符串
31fn 编译_js<'a>(
32    范围: &mut HandleScope<'a>,
33    代码: &str,
34) -> Result<Local<'a, Script>, Box<dyn Error>> {
35    // 代码转换为 v8 字符串
36    let 代码 = v8::String::new(范围, 代码).ok_or(E("v8 String::new".into()))?;
37    // 编译源代码
38    let 脚本 = Script::compile(范围, 代码, None).ok_or(E("v8 Script::compile".into()))?;
39
40    Ok(脚本)
41}
42
43/// 用来运行 JS 代码的虚拟机 (Isolate)
44#[derive(Debug)]
45pub struct Vm {
46    隔离: OwnedIsolate,
47}
48
49impl Vm {
50    /// 初始化 v8
51    pub fn new() -> Self {
52        初始化_v8();
53        let 隔离 = 创建实例();
54
55        Self { 隔离 }
56    }
57
58    /// (内部) 运行一段 JS 代码, 返回结果.
59    fn run_js<T, F>(&mut self, code: &str, f: F) -> Result<T, Box<dyn Error>>
60    where
61        F: FnOnce(&mut ContextScope<HandleScope>, Option<Local<Value>>) -> T,
62    {
63        // 创建 HandleScope, ContextScope
64        // 注意: 这段代码不能拆分 (rusty_v8 的设计如此)
65        let mut 柄范围 = HandleScope::new(&mut self.隔离);
66        let 语境 = Context::new(&mut 柄范围, Default::default());
67        let mut 范围 = ContextScope::new(&mut 柄范围, 语境);
68
69        let 脚本 = 编译_js(&mut 范围, code)?;
70        let 结果 = 脚本.run(&mut 范围);
71
72        let o = f(&mut 范围, 结果);
73        Ok(o)
74    }
75
76    /// (封装) 运行一段 JS 代码, 返回结果.
77    pub fn run_r<T, F>(&mut self, code: &str, f: F) -> Result<T, Box<dyn Error>>
78    where
79        F: FnOnce(&mut ContextScope<HandleScope>, Option<Local<Value>>) -> T,
80    {
81        self.run_js(code, f)
82    }
83
84    /// (封装) 运行一段 JS 代码, 无需结果.
85    pub fn run(&mut self, code: &str) -> Result<(), Box<dyn Error>> {
86        self.run_js(code, |_, _| ())?;
87        Ok(())
88    }
89}
90
91#[cfg(test)]
92mod tests {
93    use super::*;
94
95    #[test]
96    fn it_works() {
97        let mut vm = Vm::new();
98        let r = vm
99            .run_r(
100                "1 + 2",
101                |s: &mut ContextScope<HandleScope>, v: Option<Local<Value>>| {
102                    v.unwrap().uint32_value(s)
103                },
104            )
105            .unwrap();
106        assert_eq!(r, Some(3));
107    }
108}