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