mould_extension_sdk/
pluginator.rs1use super::AppendLog;
2use super::Attribute;
3use super::Context;
4use super::Extension;
5use super::Operation;
6pub use async_trait;
7use libloading::{Library, Symbol};
8use serde_json::Value;
9use std::fmt::Debug;
10use std::sync::Arc;
11use std::{
12 mem::ManuallyDrop,
13 ops::{Deref, DerefMut},
14};
15
16#[macro_export]
17macro_rules! plugin_trait {
18 ($plugin_trait:path) => {
19 pub unsafe fn load_plugin<Path: AsRef<std::path::Path>>(
20 path: Path,
21 ) -> Result<
22 $crate::pluginator::LoadedPlugin<dyn $plugin_trait>,
23 $crate::pluginator::LoadingError,
24 > {
25 unsafe { $crate::pluginator::load(path) }
26 }
27 };
28}
29
30#[macro_export]
31macro_rules! plugin_implementation {
32 ($plugin_trait:path, $initializer:expr) => {
33 #[no_mangle]
34 pub extern "C" fn get_interface(
35 ) -> *mut $crate::pluginator::PluginWrapper<dyn $plugin_trait> {
36 Box::into_raw(Box::new($crate::pluginator::PluginWrapper::new(Box::new(
37 $crate::pluginator::ExtensionWrapper {
38 inner: ::std::sync::Arc::new($initializer),
39 },
40 ))))
41 }
42 };
43}
44
45pub struct PluginWrapper<Plugin: ?Sized> {
46 inner: Box<Plugin>,
47}
48
49impl<Plugin: ?Sized> PluginWrapper<Plugin> {
50 pub fn new(inner: Box<Plugin>) -> Self {
51 Self { inner: inner }
52 }
53}
54
55pub struct LoadedPlugin<Plugin: ?Sized> {
56 library: ManuallyDrop<Library>,
57 plugin: ManuallyDrop<Box<Plugin>>,
58}
59
60impl<Plugin: ?Sized> Drop for LoadedPlugin<Plugin> {
61 fn drop(&mut self) {
62 unsafe {
63 ManuallyDrop::drop(&mut self.plugin);
64 ManuallyDrop::drop(&mut self.library);
65 }
66 }
67}
68
69impl<Plugin: ?Sized> Deref for LoadedPlugin<Plugin> {
70 type Target = Plugin;
71
72 fn deref(&self) -> &Self::Target {
73 self.plugin.as_ref()
74 }
75}
76
77impl<Plugin: ?Sized> DerefMut for LoadedPlugin<Plugin> {
78 fn deref_mut(&mut self) -> &mut Self::Target {
79 self.plugin.as_mut()
80 }
81}
82
83#[derive(Debug)]
84pub enum LoadingError {
85 OpeningError(libloading::Error),
86 InterfaceGettingError(libloading::Error),
87}
88
89pub unsafe fn load<Path: AsRef<std::path::Path>, Plugin: ?Sized>(
90 path: Path,
91) -> Result<LoadedPlugin<Plugin>, LoadingError> {
92 let library =
93 unsafe { Library::new(path.as_ref()) }.map_err(|e| LoadingError::OpeningError(e))?;
94 let get_interface: Symbol<fn() -> *mut PluginWrapper<Plugin>> =
95 unsafe { library.get(b"get_interface") }
96 .map_err(|e| LoadingError::InterfaceGettingError(e))?;
97 let plugin = unsafe { Box::from_raw(get_interface()) };
98 Ok(LoadedPlugin {
99 plugin: ManuallyDrop::new(plugin.inner),
100 library: ManuallyDrop::new(library),
101 })
102}
103
104pub struct ExtensionWrapper<T> {
105 pub inner: Arc<T>,
106}
107
108#[async_trait::async_trait]
109impl<T: Extension> Extension for ExtensionWrapper<T> {
110 fn id(&self) -> String {
111 self.inner.id()
112 }
113 fn name(&self) -> String {
114 self.inner.name()
115 }
116 fn configuration_schema(&self) -> Vec<Attribute> {
117 self.inner.configuration_schema()
118 }
119 fn validate_configuration(&self, configuration: Value) -> Result<(), String> {
120 self.inner.validate_configuration(configuration)
121 }
122 async fn test_configuration(
123 &self,
124 configuration: Value,
125 context: &Context,
126 ) -> Result<(), String> {
127 let _ = self
128 .inner
129 .test_configuration(configuration, context)
130 .await?;
131 Ok(())
132 }
133 fn validate_operation_parameter(
134 &self,
135 operation_id: &str,
136 operation_parameter: Value,
137 ) -> Result<(), String> {
138 self.inner
139 .validate_operation_parameter(operation_id, operation_parameter)
140 }
141 fn operations(&self) -> Vec<Operation> {
142 self.inner.operations()
143 }
144 async fn handle(
145 &self,
146 configuration: Value,
147 operation_id: &str,
148 operation_parameter: Value,
149 context: &Context,
150 append_log: &AppendLog,
151 resource_index: u32,
152 ) -> Result<(), String> {
153 self.inner
154 .handle(
155 configuration,
156 operation_id,
157 operation_parameter,
158 context,
159 append_log,
160 resource_index,
161 )
162 .await
163 }
164}