rquickjs_core/loader/
native_loader.rs

1use crate::{loader::util::check_extensions, module::ModuleLoadFn, Ctx, Error, Module, Result};
2
3use super::Loader;
4
5/// The native module loader
6///
7/// This loader can be used as the nested backing loader in user-defined loaders.
8#[cfg_attr(feature = "doc-cfg", doc(cfg(feature = "dyn-load")))]
9#[derive(Debug)]
10pub struct NativeLoader {
11    extensions: Vec<String>,
12    libs: Vec<dlopen::raw::Library>,
13}
14
15impl NativeLoader {
16    /// Add library file extension
17    pub fn add_extension<X: Into<String>>(&mut self, extension: X) -> &mut Self {
18        self.extensions.push(extension.into());
19        self
20    }
21
22    /// Add library file extension
23    pub fn with_extension<X: Into<String>>(&mut self, extension: X) -> &mut Self {
24        self.add_extension(extension);
25        self
26    }
27}
28
29impl Default for NativeLoader {
30    fn default() -> Self {
31        let mut loader = Self {
32            extensions: Vec::new(),
33            libs: Vec::new(),
34        };
35
36        #[cfg(target_family = "windows")]
37        loader.add_extension("dll");
38
39        #[cfg(target_family = "unix")]
40        loader.add_extension("so");
41
42        #[cfg(target_vendor = "apple")]
43        loader.add_extension("dylib");
44
45        loader
46    }
47}
48
49impl Loader for NativeLoader {
50    fn load<'js>(&mut self, ctx: &Ctx<'js>, path: &str) -> Result<Module<'js>> {
51        use dlopen::raw::Library;
52
53        if !check_extensions(path, &self.extensions) {
54            return Err(Error::new_loading(path));
55        }
56
57        let lib = Library::open(path)
58            .map_err(|_| Error::new_loading_message(path, "Unable to open library"))?;
59        let load: ModuleLoadFn = unsafe { lib.symbol("js_init_module") }.map_err(|_| {
60            Error::new_loading_message(path, "Unable to find symbol `js_init_module`")
61        })?;
62
63        let module = unsafe { Module::from_load_fn(ctx.clone(), path, load)? };
64
65        self.libs.push(lib);
66
67        Ok(module)
68    }
69}