Skip to main content

mould_extension_sdk/
pluginator.rs

1use 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}