use crate::{loader::util::check_extensions, module::ModuleLoadFn, Ctx, Error, Module, Result};
use super::Loader;
#[cfg_attr(feature = "doc-cfg", doc(cfg(feature = "dyn-load")))]
#[derive(Debug)]
pub struct NativeLoader {
extensions: Vec<String>,
libs: Vec<dlopen::raw::Library>,
}
impl NativeLoader {
pub fn add_extension<X: Into<String>>(&mut self, extension: X) -> &mut Self {
self.extensions.push(extension.into());
self
}
pub fn with_extension<X: Into<String>>(&mut self, extension: X) -> &mut Self {
self.add_extension(extension);
self
}
}
impl Default for NativeLoader {
fn default() -> Self {
let mut loader = Self {
extensions: Vec::new(),
libs: Vec::new(),
};
#[cfg(target_family = "windows")]
loader.add_extension("dll");
#[cfg(target_family = "unix")]
loader.add_extension("so");
#[cfg(target_vendor = "apple")]
loader.add_extension("dylib");
loader
}
}
impl Loader for NativeLoader {
fn load<'js>(&mut self, ctx: &Ctx<'js>, path: &str) -> Result<Module<'js>> {
use dlopen::raw::Library;
if !check_extensions(path, &self.extensions) {
return Err(Error::new_loading(path));
}
let lib = Library::open(path)
.map_err(|_| Error::new_loading_message(path, "Unable to open library"))?;
let load: ModuleLoadFn = unsafe { lib.symbol("js_init_module") }.map_err(|_| {
Error::new_loading_message(path, "Unable to find symbol `js_init_module`")
})?;
let module = unsafe { Module::from_load_fn(ctx.clone(), path, load)? };
self.libs.push(lib);
Ok(module)
}
}