#![doc = include_str!("../README.md")]
#![warn(missing_docs)]
#![allow(non_local_definitions)] // triggered for code generated by abi_stable macros
mod proxy;
#[rustfmt::skip]
#[path = "gen/api.rs"]
mod api;
use std::{
fmt,
path::Path,
sync::{Arc, LazyLock},
};
use abi_stable::library::lib_header_from_path;
pub use crate::api::*;
// This is not a public API. Use export_plugin! macro for plugin exporting.
#[doc(hidden)]
pub use crate::proxy::PluginMod_Ref;
/// Exports the plugin that will instantiated with the specified expression.
///
/// # Examples
///
/// ```
/// use openrr_plugin::Plugin;
///
/// openrr_plugin::export_plugin!(MyPlugin);
///
/// pub struct MyPlugin;
///
/// impl Plugin for MyPlugin {
/// }
/// ```
#[macro_export]
macro_rules! export_plugin {
($plugin_constructor:expr $(,)?) => {
/// Exports the root module of this library.
///
/// This code isn't run until the layout of the type it returns is checked.
#[allow(clippy::drop_non_drop)] // this lint is triggered for code generated by #[export_root_module]
#[::abi_stable::export_root_module]
pub fn instantiate_root_module() -> $crate::PluginMod_Ref {
$crate::PluginMod_Ref::new(plugin_constructor)
}
/// Instantiates the plugin.
#[allow(clippy::drop_non_drop)] // this lint is triggered for code generated by #[export_root_module]
#[::abi_stable::sabi_extern_fn]
pub fn plugin_constructor() -> $crate::PluginProxy {
$crate::PluginProxy::new($plugin_constructor)
}
};
}
impl PluginProxy {
/// Loads a plugin from the specified path.
pub fn from_path(path: impl AsRef<Path>) -> Result<Self, arci::Error> {
let path = path.as_ref();
let header = lib_header_from_path(path).map_err(anyhow::Error::from)?;
let root_module = header
.init_root_module::<PluginMod_Ref>()
.map_err(anyhow::Error::from)?;
let plugin_constructor = root_module.plugin_constructor();
let plugin = plugin_constructor();
Ok(plugin)
}
}
impl fmt::Debug for PluginProxy {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("PluginProxy").finish()
}
}
// Inspired by async-compat.
static TOKIO: LazyLock<tokio::runtime::Runtime> = LazyLock::new(|| {
std::thread::Builder::new()
.name("openrr-plugin/tokio".to_owned())
.spawn(move || TOKIO.block_on(std::future::pending::<()>()))
.unwrap();
tokio::runtime::Builder::new_multi_thread()
.enable_all()
.build()
.expect("cannot start tokio runtime")
});