intuicio_plugins/
lib.rs

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
use intuicio_core::{crate_version, registry::Registry, IntuicioVersion};
use libloading::Library;
use std::{cell::RefCell, collections::HashMap};

thread_local! {
    static LIBRARIES: RefCell<HashMap<String, Library>> = Default::default();
}

#[derive(Debug, Copy, Clone)]
pub struct IncompatibleVersionsError {
    pub host: IntuicioVersion,
    pub plugin: IntuicioVersion,
}

impl std::fmt::Display for IncompatibleVersionsError {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        write!(
            f,
            "Incompatible host ({}) and plugin ({}) versions!",
            self.host, self.plugin
        )
    }
}

impl std::error::Error for IncompatibleVersionsError {}

pub fn install_plugin(
    path: &str,
    registry: &mut Registry,
    host_version: Option<IntuicioVersion>,
) -> Result<(), Box<dyn std::error::Error>> {
    unsafe {
        let host_version = host_version.unwrap_or_else(plugins_version);
        let library = Library::new(path)?;
        let version = library.get::<unsafe extern "C" fn() -> IntuicioVersion>(b"version\0")?;
        let plugin_version = version();
        if !host_version.is_compatible(&plugin_version) {
            return Err(Box::new(IncompatibleVersionsError {
                host: host_version,
                plugin: plugin_version,
            }));
        }
        let install = library.get::<unsafe extern "C" fn(&mut Registry)>(b"install\0")?;
        install(registry);
        LIBRARIES.with(|map| map.borrow_mut().insert(path.to_owned(), library));
        Ok(())
    }
}

pub fn plugins_version() -> IntuicioVersion {
    crate_version!()
}