player_plugin_loader/
native_library.rs1use std::mem::ManuallyDrop;
2use std::path::Path;
3use std::sync::Arc;
4
5use libloading::Library;
6use thiserror::Error;
7
8use crate::native_abi::CheckedPluginRoot;
9use crate::{LoadedNativePlugin, NativePluginContractError};
10
11#[derive(Debug, Error)]
12pub enum PluginLoadError {
13 #[error("failed to open plugin library at {path}: {source}")]
14 OpenLibrary {
15 path: String,
16 #[source]
17 source: libloading::Error,
18 },
19 #[error("failed to resolve plugin entry symbol `{symbol}`: {source}")]
20 ResolveEntrySymbol {
21 symbol: &'static str,
22 #[source]
23 source: libloading::Error,
24 },
25 #[error("native plugin root violates the ABI contract: {0}")]
26 NativeContract(#[from] NativePluginContractError),
27}
28
29impl LoadedNativePlugin {
30 pub fn load_development(path: impl AsRef<Path>) -> Result<Self, PluginLoadError> {
36 let path = path.as_ref();
37 tracing::warn!(
38 path = %path.display(),
39 "loading an unsigned raw Native plugin library under explicit development policy"
40 );
41 Self::load_unchecked(path)
42 }
43
44 pub(crate) fn load_host_verified(path: impl AsRef<Path>) -> Result<Self, PluginLoadError> {
45 Self::load_unchecked(path.as_ref())
46 }
47
48 fn load_unchecked(path: &Path) -> Result<Self, PluginLoadError> {
49 let path_string = path.display().to_string();
50 let library =
54 unsafe { Library::new(path) }.map_err(|source| PluginLoadError::OpenLibrary {
55 path: path_string,
56 source,
57 })?;
58 let library = Arc::new(LibraryHolder {
59 library: ManuallyDrop::new(library),
60 });
61
62 let entry = unsafe {
65 library
66 .library
67 .get::<player_plugin_abi::VesperPluginEntryPoint>(
68 player_plugin_abi::VESPER_PLUGIN_ENTRY_SYMBOL,
69 )
70 }
71 .map_err(|source| PluginLoadError::ResolveEntrySymbol {
72 symbol: player_plugin_abi::VESPER_PLUGIN_ENTRY_SYMBOL_NAME,
73 source,
74 })?;
75
76 let root = unsafe { entry() };
78 let checked =
79 unsafe { CheckedPluginRoot::from_raw(root, Some(library)) }?;
82 Ok(Self::from_checked(checked))
83 }
84}
85
86#[derive(Debug)]
87pub(crate) struct LibraryHolder {
88 #[allow(dead_code)]
91 pub(crate) library: ManuallyDrop<Library>,
92}