1use std::any::Any;
2use libloading::{Library, Symbol};
3
4#[macro_export]
6macro_rules! racker_plugin {
7 ($pl_t:ty, $pl_c:path) => {
8 #[no_mangle]
9 pub extern "C" fn _racker_plugin_create() -> *mut dyn $crate::Plugin {
10 let constructor: fn() -> $pl_t = $pl_c;
11 let plugin = constructor();
12 Box::into_raw(Box::new(plugin))
13 }
14 };
15}
16
17pub trait Plugin: Any + Send + Sync {
18 fn meta(&self) -> PluginMeta;
20
21 fn on_load(&self);
23
24 fn on_unload(&self);
26}
27
28pub struct PluginMeta {
29 pub name: String,
30 pub version: String,
31 pub description: String,
32 pub author: String,
33}
34
35pub struct PluginManager {
36 plugins: Vec<Box<dyn Plugin>>,
37 loaded_libraries: Vec<Library>,
38}
39
40impl PluginManager {
41 pub fn create() -> Self {
42 Self { plugins: Vec::new(), loaded_libraries: Vec::new() }
43 }
44
45 pub fn load_plugin_from_file(&mut self, path: &str) {
46 unsafe {
47 let lib = Library::new(path).unwrap();
48 let create: Symbol<unsafe fn() -> *mut dyn Plugin> = lib.get(b"_racker_plugin_create").unwrap();
49 let plugin = create();
50 let plugin = Box::from_raw(plugin);
51
52 plugin.on_load();
53
54 self.plugins.push(plugin);
55 self.loaded_libraries.push(lib);
56 }
57 }
58
59 pub fn load_plugin(&mut self, plugin: Box<dyn Plugin>) {
60 plugin.on_load();
61 self.plugins.push(plugin);
62 }
63
64 pub fn unload_plugin(&mut self, name: &str) {
65 let mut index = None;
66 for (i, plugin) in self.plugins.iter().enumerate() {
67 if plugin.meta().name == name {
68 index = Some(i);
69 break;
70 }
71 }
72
73 if let Some(i) = index {
74 self.plugins[i].on_unload();
75 self.plugins.remove(i);
76 }
77 }
78}