1use std::io;
2
3use anyhow::{Context, Result, bail};
4use libloading::Library;
5use plugin_api::Plugin;
6use tempfile::NamedTempFile;
7
8use crate::LocatedPlugin;
9
10pub struct LoadedPlugin {
11 pub located: LocatedPlugin,
12 pub plugin: Box<dyn Plugin>,
13 // DO NOT MOVE THIS UP!
14 // This is due to rust's dropping order!
15 // If the library gets dropped (unloaded) before the plugin, a segfault will occur.
16 pub lib: Library,
17}
18
19pub fn load(mut plugin: LocatedPlugin) -> Result<LoadedPlugin> {
20 #[cfg(target_os = "linux")]
21 let cdylib = plugin.so;
22
23 #[cfg(target_os = "windows")]
24 let cdylib = plugin.dll;
25
26 #[cfg(target_os = "macos")]
27 let cdylib = plugin.dylib;
28
29 if !cdylib {
30 bail!("unsupported platform");
31 }
32
33 #[cfg(target_os = "linux")]
34 let cdylib = "plugin.so";
35
36 #[cfg(target_os = "windows")]
37 let cdylib = "plugin.dll";
38
39 #[cfg(target_os = "macos")]
40 let cdylib = "plugin.dylib";
41
42 let mut tmp = NamedTempFile::new().context("failed creating temp file")?;
43 {
44 let mut entry = plugin.zip.by_name(cdylib).unwrap();
45 io::copy(&mut entry, &mut tmp).context("failed copying cdylib to temp file")?;
46 }
47
48 unsafe {
49 let lib =
50 Library::new(tmp.path().display().to_string()).context("failed loading library")?;
51 let ctor = lib
52 .get::<unsafe extern "Rust" fn() -> Box<dyn Plugin>>(b"provide_plugin")
53 .context("plugin does not have a provide_plugin function")?;
54 let instance = ctor();
55
56 Ok(LoadedPlugin {
57 located: plugin,
58 lib,
59 plugin: instance,
60 })
61 }
62}