deft_quick_js/
loader.rs

1//! js module loader
2use std::ffi::{c_char, CStr, CString};
3use std::fs::File;
4use std::io;
5use std::io::{Error, Read};
6use std::os::raw::c_int;
7use std::path::PathBuf;
8use std::ptr::null_mut;
9use std::str::FromStr;
10use libquickjs_sys::{JS_Eval, JS_EVAL_FLAG_COMPILE_ONLY, JS_EVAL_TYPE_MODULE, JS_FreeValue, JS_IsException, JSContext, JSModuleDef, size_t, JS_VALUE_GET_PTR};
11
12/// js module loader callback
13pub unsafe extern "C" fn quickjs_rs_module_loader(
14        ctx: *mut JSContext,
15        module_name: *const ::std::os::raw::c_char,
16        opaque: *mut ::std::os::raw::c_void,
17    ) -> *mut JSModuleDef {
18    let module_name = CStr::from_ptr(module_name);
19    println!("loading module:{:?}", module_name);
20    let mut loader = &mut *(opaque as *mut _ as *mut Box<dyn JsModuleLoader>);
21    let input =  match loader.load(module_name.to_str().unwrap()) {
22        Ok(e) => e,
23        Err(err) => {
24            return null_mut()
25        }
26    };
27    let code_len = input.len();
28    let code = CString::new(input).unwrap();
29    let func_val = JS_Eval(
30        ctx,
31        code.as_ptr() as *const c_char,
32        code_len as size_t,
33        module_name.as_ptr(),
34        (JS_EVAL_TYPE_MODULE | JS_EVAL_FLAG_COMPILE_ONLY) as c_int
35    );
36    if JS_IsException(func_val) {
37        return null_mut();
38        // return Err(anyhow!("Failed to load module"));
39    }
40    // js_module_set_import_meta(ctx, func_val, true as c_int, false as c_int);
41    let ptr = JS_VALUE_GET_PTR(func_val);
42    JS_FreeValue(ctx, func_val);
43    ptr as *mut JSModuleDef
44}
45
46/// js module loader trait
47pub trait JsModuleLoader: 'static {
48    /// load a module
49    fn load(&mut self, module_name: &str) -> Result<String, io::Error>;
50}
51
52/// File system module loader
53pub struct FsJsModuleLoader {
54    base: PathBuf,
55}
56
57impl FsJsModuleLoader {
58
59    /// create a new FsJsModuleLoader
60    pub fn new(base: &str) -> Self {
61        Self {
62            base: PathBuf::from_str(base).unwrap()
63        }
64    }
65}
66
67impl JsModuleLoader for FsJsModuleLoader {
68    fn load(&mut self, module_name: &str) -> Result<String, Error> {
69        let path = self.base.join(module_name);
70        let mut file = File::open(path)?;
71        let mut content = String::new();
72        file.read_to_string(&mut content)?;
73        Ok(content)
74    }
75}