use std::ffi::c_void;
use std::os::raw::{c_char, c_int};
pub use xplm_sys::XPLMPluginID;
pub trait XPlanePlugin: Sized + 'static {
const NAME: &'static str = "";
const SIGNATURE: &'static str = "";
const DESCRIPTION: &'static str = "";
fn start() -> Self;
fn enable(&mut self) -> bool {
true
}
fn disable(&mut self) {}
fn stop(self) {}
fn receive_message(
&mut self,
from_plugin_id: XPLMPluginID,
message: c_int,
param: *mut c_void,
) {
let _ = (from_plugin_id, message, param);
}
}
pub unsafe fn write_c_string(dest: *mut c_char, value: &str) {
if dest.is_null() {
return;
}
const CAPACITY: usize = 256;
let bytes = value.as_bytes();
let len = bytes.len().min(CAPACITY - 1);
unsafe {
std::ptr::copy_nonoverlapping(bytes.as_ptr() as *const c_char, dest, len);
*dest.add(len) = 0;
}
}
#[macro_export]
macro_rules! register_plugin {
($t:ty) => {
$crate::register_plugin!(
@impl
$t,
<$t as $crate::plugin::XPlanePlugin>::NAME,
<$t as $crate::plugin::XPlanePlugin>::SIGNATURE,
<$t as $crate::plugin::XPlanePlugin>::DESCRIPTION
);
};
($t:ty, name = $name:expr, signature = $signature:expr, description = $description:expr) => {
$crate::register_plugin!(@impl $t, $name, $signature, $description);
};
(@impl $t:ty, $name:expr, $signature:expr, $description:expr) => {
static XPLM_PLUGIN_STATE: ::std::sync::Mutex<::std::option::Option<$t>> =
::std::sync::Mutex::new(::std::option::Option::None);
#[no_mangle]
pub extern "C" fn XPluginStart(
out_name: *mut ::std::os::raw::c_char,
out_sig: *mut ::std::os::raw::c_char,
out_desc: *mut ::std::os::raw::c_char,
) -> ::std::os::raw::c_int {
unsafe {
$crate::plugin::write_c_string(out_name, $name);
$crate::plugin::write_c_string(out_sig, $signature);
$crate::plugin::write_c_string(out_desc, $description);
}
$crate::guard(|| {
let plugin = <$t as $crate::plugin::XPlanePlugin>::start();
*XPLM_PLUGIN_STATE.lock().unwrap() = ::std::option::Option::Some(plugin);
});
1
}
#[no_mangle]
pub extern "C" fn XPluginStop() {
$crate::guard(|| {
if let ::std::option::Option::Some(plugin) =
XPLM_PLUGIN_STATE.lock().unwrap().take()
{
<$t as $crate::plugin::XPlanePlugin>::stop(plugin);
}
});
}
#[no_mangle]
pub extern "C" fn XPluginEnable() -> ::std::os::raw::c_int {
$crate::guard(|| match XPLM_PLUGIN_STATE.lock().unwrap().as_mut() {
::std::option::Option::Some(plugin) => {
<$t as $crate::plugin::XPlanePlugin>::enable(plugin) as ::std::os::raw::c_int
}
::std::option::Option::None => 0,
})
.unwrap_or(0)
}
#[no_mangle]
pub extern "C" fn XPluginDisable() {
$crate::guard(|| {
if let ::std::option::Option::Some(plugin) =
XPLM_PLUGIN_STATE.lock().unwrap().as_mut()
{
<$t as $crate::plugin::XPlanePlugin>::disable(plugin);
}
});
}
#[no_mangle]
pub extern "C" fn XPluginReceiveMessage(
from_who: $crate::plugin::XPLMPluginID,
message: ::std::os::raw::c_int,
param: *mut ::std::os::raw::c_void,
) {
$crate::guard(|| {
if let ::std::option::Option::Some(plugin) =
XPLM_PLUGIN_STATE.lock().unwrap().as_mut()
{
<$t as $crate::plugin::XPlanePlugin>::receive_message(
plugin, from_who, message, param,
);
}
});
}
};
}