1use 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
12pub 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 }
40 let ptr = JS_VALUE_GET_PTR(func_val);
42 JS_FreeValue(ctx, func_val);
43 ptr as *mut JSModuleDef
44}
45
46pub trait JsModuleLoader: 'static {
48 fn load(&mut self, module_name: &str) -> Result<String, io::Error>;
50}
51
52pub struct FsJsModuleLoader {
54 base: PathBuf,
55}
56
57impl FsJsModuleLoader {
58
59 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}