racker_plugin/
lib.rs

1use std::any::Any;
2use libloading::{Library, Symbol};
3
4/// Declares a plugin.
5#[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    /// Returns the plugin's metadata.
19    fn meta(&self) -> PluginMeta;
20
21    /// Called when the plugin is loaded.
22    fn on_load(&self);
23
24    /// Called when the plugin is unloaded.
25    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}