use std::path::Path;
use libloading::{Library, Symbol};
use crate::traits::Plugin;
pub struct RustPluginLoader {
_libraries: Vec<Library>,
plugins: Vec<Box<dyn Plugin>>,
}
impl RustPluginLoader {
pub fn new() -> Self {
Self {
_libraries: Vec::new(),
plugins: Vec::new(),
}
}
pub unsafe fn load(
&mut self,
path: &Path,
) -> std::result::Result<&dyn Plugin, Box<dyn std::error::Error + Send + Sync>> {
let lib = unsafe { Library::new(path) }.map_err(|e| {
Box::new(std::io::Error::other(format!(
"failed to load plugin library {}: {e}",
path.display()
)))
})?;
let constructor: Symbol<unsafe extern "C" fn() -> *mut dyn Plugin> =
unsafe { lib.get(b"create_plugin") }.map_err(|e| {
Box::new(std::io::Error::other(format!(
"plugin library {} missing create_plugin symbol: {e}",
path.display()
)))
})?;
let raw = unsafe { constructor() };
if raw.is_null() {
return Err(Box::new(std::io::Error::other(format!(
"create_plugin returned null in {}",
path.display()
))));
}
let plugin = unsafe { Box::from_raw(raw) };
self.plugins.push(plugin);
self._libraries.push(lib);
Ok(self.plugins.last().unwrap().as_ref())
}
pub fn plugins(&self) -> &[Box<dyn Plugin>] {
&self.plugins
}
pub fn into_plugins(self) -> Vec<Box<dyn Plugin>> {
self.plugins
}
}
impl Default for RustPluginLoader {
fn default() -> Self {
Self::new()
}
}