1use std::path::Path;
2
3use libloading::{Library, Symbol};
4
5use crate::traits::Plugin;
6
7pub struct RustPluginLoader {
12 _libraries: Vec<Library>,
14 plugins: Vec<Box<dyn Plugin>>,
16}
17
18impl RustPluginLoader {
19 pub fn new() -> Self {
20 Self {
21 _libraries: Vec::new(),
22 plugins: Vec::new(),
23 }
24 }
25
26 pub unsafe fn load(
35 &mut self,
36 path: &Path,
37 ) -> std::result::Result<&dyn Plugin, Box<dyn std::error::Error + Send + Sync>> {
38 let lib = unsafe { Library::new(path) }.map_err(|e| {
40 Box::new(std::io::Error::other(format!(
41 "failed to load plugin library {}: {e}",
42 path.display()
43 )))
44 })?;
45
46 let constructor: Symbol<unsafe extern "C" fn() -> *mut dyn Plugin> =
48 unsafe { lib.get(b"create_plugin") }.map_err(|e| {
49 Box::new(std::io::Error::other(format!(
50 "plugin library {} missing create_plugin symbol: {e}",
51 path.display()
52 )))
53 })?;
54
55 let raw = unsafe { constructor() };
56 if raw.is_null() {
57 return Err(Box::new(std::io::Error::other(format!(
58 "create_plugin returned null in {}",
59 path.display()
60 ))));
61 }
62 let plugin = unsafe { Box::from_raw(raw) };
63
64 self.plugins.push(plugin);
65 self._libraries.push(lib);
66
67 Ok(self.plugins.last().unwrap().as_ref())
69 }
70
71 pub fn plugins(&self) -> &[Box<dyn Plugin>] {
73 &self.plugins
74 }
75
76 pub fn into_plugins(self) -> Vec<Box<dyn Plugin>> {
78 self.plugins
79 }
80}
81
82impl Default for RustPluginLoader {
83 fn default() -> Self {
84 Self::new()
85 }
86}