use super::errors::OvertoneApiError;
use super::project::Project;
use crate::serialization::project::PluginDependencyEntry;
use libloading::Library;
use std::fmt::Debug;
use std::path::PathBuf;
#[allow(dead_code)]
pub trait Plugin {
fn get_id(&self) -> &'static str;
fn get_name(&self) -> &'static str {
return "a";
}
fn on_plugin_load(&mut self, _project: &Project) {}
}
pub struct PluginIdType(());
pub type PluginId = i32;
pub type PluginGetterFn = unsafe fn() -> Box<dyn Plugin>;
pub struct LoadedPlugin<'a> {
pub uid: PluginId,
pub plugin: Box<dyn Plugin>,
pub source: &'a PluginDependencyEntry,
lib: Library,
}
pub const PLUGIN_GETTER_SYMBOL: &'static [u8; 10] = b"get_plugin";
impl<'a> LoadedPlugin<'a> {
pub fn get_uid(&self) -> &PluginId {
return &self.uid;
}
pub fn get_plugin(&self) -> &Box<dyn Plugin> {
return &self.plugin;
}
pub fn get_lib(&'a self) -> &'a Library {
return &self.lib;
}
pub fn from_dependency_decl(
base_path: &Option<PathBuf>,
source: &'a PluginDependencyEntry,
) -> Result<LoadedPlugin<'a>, OvertoneApiError> {
let path = base_path.as_ref().map_or_else(
|| PathBuf::from(source.path.clone()),
|b_p| b_p.join(source.path.clone()),
);
let lib: libloading::Library;
let plugin: Box<dyn Plugin>;
unsafe {
let l = libloading::Library::new(path);
lib = l.map_err(|e| OvertoneApiError::LibraryNotFound(e))?;
let plugin_getter = lib
.get::<PluginGetterFn>(PLUGIN_GETTER_SYMBOL)
.map_err(|_| OvertoneApiError::LibraryIsNotOvertonePlugin())?;
plugin = plugin_getter();
}
Ok(LoadedPlugin {
uid: 0,
lib,
source,
plugin,
})
}
}
impl<'a> Debug for LoadedPlugin<'a> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.write_str(format!("[Plugin '{}']", self.plugin.get_name()).as_str())
}
}