plugin_macros/
lib.rs

1use libloading::{Library, Symbol};
2use std::{any::Any, ffi::OsStr};
3
4#[cfg_attr(not(feature = "nightly"), macro_use)]
5#[cfg(not(feature = "nightly"))]
6extern crate failure;
7
8#[cfg(not(feature = "nightly"))]
9extern crate libloading;
10
11#[cfg(all(not(feature = "nightly"), feature = "hashbrown"))]
12extern crate hashbrown;
13
14#[cfg(all(not(feature = "nightly"), feature = "fx"))]
15extern crate fxhash;
16
17#[cfg(feature = "swisstable")]
18use hashbrown::HashMap;
19#[cfg(feature = "fx")]
20use fxhash::FxHashMap as HashMap;
21#[cfg(all(not(feature = "swisstable"), not(feature = "fx")))]
22use std::collections::HashMap;
23
24pub mod error;
25
26pub trait Plugin: Any + Send + Sync {
27    fn load(&mut self) {}
28    fn unload(&mut self) {}
29}
30
31#[macro_export]
32macro_rules! declare_plugin {
33    ($type:ty, $instance:expr) => {
34        #[no_mangle]
35        pub extern "C" fn _plugin_create() -> *mut $crate::Plugin {
36            let object: $type = $instance;
37            let boxed: Box<$crate::Plugin> = Box::new(object);
38            Box::into_raw(boxed)
39        }
40    };
41}
42
43pub struct PluginManager {
44    plugins: HashMap<String, Box<Plugin>>,
45    libraries: HashMap<String, Library>,
46}
47
48impl PluginManager {
49    #[inline]
50    pub fn new() -> Self {
51        PluginManager {
52            plugins: HashMap::default(),
53            libraries: HashMap::default(),
54        }
55    }
56
57    pub fn get_by_file_name(&self, name: &String) -> Option<&Box<Plugin>> {
58        self.plugins.get(name)
59    }
60
61    pub unsafe fn get_library_by_file_name(&self, name: &String) -> Option<&Library> {
62        self.libraries.get(name)
63    }
64
65    pub fn load_plugin<P>(&mut self, path: P) -> error::Result<()>
66    where
67        P: AsRef<OsStr>,
68    {
69        let file = path.as_ref();
70        let file_str = match file.to_str().map(|s| s.to_owned()) {
71            Some(s) => s,
72            None => return Err(error::PluginError::UndecodableName.into()),
73        };
74        let library = Library::new(file)?;
75        self.libraries.insert(file_str.clone(), library);
76
77        let mut instance = unsafe {
78            let func: Symbol<fn() -> *mut Plugin> = self
79                .libraries
80                .get(&file_str)
81                .unwrap()
82                .get(b"_plugin_create")?;
83            Box::from_raw(func())
84        };
85
86        instance.load();
87        self.plugins.insert(file_str, instance);
88
89        Ok(())
90    }
91
92    pub fn unload_plugins(&mut self) {
93        for (_, mut plugin) in self.plugins.drain() {
94            plugin.unload();
95            drop(plugin);
96        }
97        for (_, lib) in self.libraries.drain() {
98            drop(lib);
99        }
100    }
101}
102
103impl Drop for PluginManager {
104    fn drop(&mut self) {
105        self.unload_plugins();
106    }
107}