sh_layer4/plugin_loader/
abi.rs1use abi_stable::std_types::RString;
6use abi_stable::StableAbi;
7use serde::{Deserialize, Serialize};
8
9#[repr(C)]
11#[derive(Debug, Clone, StableAbi, Serialize, Deserialize)]
12pub struct StablePluginMeta {
13 pub name: RString,
14 pub version: RString,
15 pub author: RString,
16 pub description: RString,
17}
18
19impl Default for StablePluginMeta {
20 fn default() -> Self {
21 Self {
22 name: RString::from("unknown"),
23 version: RString::from("0.1.0"),
24 author: RString::from("unknown"),
25 description: RString::new(),
26 }
27 }
28}
29
30impl From<super::PluginMeta> for StablePluginMeta {
31 fn from(meta: super::PluginMeta) -> Self {
32 Self {
33 name: RString::from(meta.name),
34 version: RString::from(meta.version),
35 author: RString::from(meta.author),
36 description: RString::from(meta.description),
37 }
38 }
39}
40
41impl From<StablePluginMeta> for super::PluginMeta {
42 fn from(meta: StablePluginMeta) -> Self {
43 Self {
44 name: meta.name.into_string(),
45 version: meta.version.into_string(),
46 author: meta.author.into_string(),
47 description: meta.description.into_string(),
48 ..Default::default()
49 }
50 }
51}
52
53#[repr(C)]
55pub struct PluginEntryPoint {
56 pub create: extern "C" fn() -> *mut std::ffi::c_void,
58 pub destroy: extern "C" fn(*mut std::ffi::c_void),
60 pub meta: extern "C" fn() -> StablePluginMeta,
62}
63
64#[macro_export]
66macro_rules! declare_stable_plugin {
67 ($plugin_type:ty, $name:expr, $version:expr) => {
68 static mut PLUGIN_INSTANCE: Option<Box<$plugin_type>> = None;
69
70 #[no_mangle]
71 pub extern "C" fn plugin_create() -> *mut std::ffi::c_void {
72 unsafe {
73 PLUGIN_INSTANCE = Some(Box::new(<$plugin_type>::default()));
74 PLUGIN_INSTANCE.as_mut().unwrap().as_mut() as *mut _ as *mut std::ffi::c_void
75 }
76 }
77
78 #[no_mangle]
79 pub extern "C" fn plugin_destroy(_ptr: *mut std::ffi::c_void) {
80 unsafe {
81 PLUGIN_INSTANCE = None;
82 }
83 }
84
85 #[no_mangle]
86 pub extern "C" fn plugin_meta() -> $crate::plugin_loader::abi::StablePluginMeta {
87 $crate::plugin_loader::abi::StablePluginMeta {
88 name: abi_stable::std_types::RString::from($name),
89 version: abi_stable::std_types::RString::from($version),
90 ..Default::default()
91 }
92 }
93 };
94}
95
96#[cfg(test)]
97mod tests {
98 use super::*;
99
100 #[test]
101 fn test_stable_plugin_meta_default() {
102 let meta = StablePluginMeta::default();
103 assert_eq!(meta.name.as_str(), "unknown");
104 assert_eq!(meta.version.as_str(), "0.1.0");
105 }
106
107 #[test]
108 fn test_stable_plugin_meta_conversion() {
109 let original = super::super::PluginMeta {
110 name: "test".to_string(),
111 version: "1.0.0".to_string(),
112 author: "tester".to_string(),
113 description: "test plugin".to_string(),
114 ..Default::default()
115 };
116
117 let stable: StablePluginMeta = original.clone().into();
118 assert_eq!(stable.name.as_str(), "test");
119
120 let back: super::super::PluginMeta = stable.into();
121 assert_eq!(back.name, "test");
122 assert_eq!(back.version, "1.0.0");
123 }
124}