use std::mem::ManuallyDrop;
use necsim_core::reporter::{
boolean::{Boolean, True},
Reporter,
};
pub trait SerializeableReporter: Reporter + erased_serde::Serialize {
fn reporter_name(&self) -> &'static str;
}
pub struct ReporterPluginDeclaration {
pub rustc_version: &'static str,
pub core_version: &'static str,
#[allow(improper_ctypes_definitions)]
pub init: unsafe extern "C" fn(&'static dyn log::Log, log::LevelFilter),
#[allow(improper_ctypes_definitions)]
pub deserialise:
unsafe extern "C" fn(
&mut dyn erased_serde::Deserializer,
)
-> Result<ManuallyDrop<UnsafeReporterPlugin>, erased_serde::Error>,
#[allow(improper_ctypes_definitions)]
pub library_path: unsafe extern "C" fn() -> Option<::std::path::PathBuf>,
#[allow(improper_ctypes_definitions)]
pub drop: unsafe extern "C" fn(ManuallyDrop<UnsafeReporterPlugin>),
}
#[derive(Copy, Clone)]
#[allow(dead_code)]
pub struct ReporterPluginFilter {
pub(crate) report_speciation: bool,
pub(crate) report_dispersal: bool,
pub(crate) report_progress: bool,
}
impl ReporterPluginFilter {
#[must_use]
pub fn from_reporter<R: SerializeableReporter>() -> Self {
Self {
report_speciation: R::ReportSpeciation::VALUE,
report_dispersal: R::ReportDispersal::VALUE,
report_progress: R::ReportProgress::VALUE,
}
}
}
pub type DynReporterPlugin = dyn SerializeableReporter<
ReportSpeciation = True,
ReportDispersal = True,
ReportProgress = True,
>;
#[repr(C)]
pub struct UnsafeReporterPlugin {
pub(crate) reporter: Box<DynReporterPlugin>,
pub(crate) filter: ReporterPluginFilter,
}
impl<R: SerializeableReporter> From<R> for UnsafeReporterPlugin {
fn from(reporter: R) -> Self {
let boxed_reporter: Box<
dyn SerializeableReporter<
ReportSpeciation = R::ReportSpeciation,
ReportDispersal = R::ReportDispersal,
ReportProgress = R::ReportProgress,
>,
> = Box::new(reporter);
Self {
reporter: unsafe {
std::mem::transmute::<
Box<
dyn SerializeableReporter<
ReportDispersal = R::ReportDispersal,
ReportProgress = R::ReportProgress,
ReportSpeciation = R::ReportSpeciation,
>,
>,
Box<
dyn SerializeableReporter<
ReportDispersal = True,
ReportProgress = True,
ReportSpeciation = True,
>,
>,
>(boxed_reporter)
},
filter: ReporterPluginFilter::from_reporter::<R>(),
}
}
}
#[macro_export]
#[allow(clippy::module_name_repetitions)]
macro_rules! export_plugin {
($($name:ident => $plugin:ty),+$(,)?) => {
#[doc(hidden)]
extern "C" fn __necsim_reporter_plugin_init(
log: &'static dyn $crate::log::Log,
max_level: $crate::log::LevelFilter,
) {
let _ = $crate::log::set_logger(log);
$crate::log::set_max_level(max_level);
}
#[doc(hidden)]
extern "C" fn __necsim_reporter_plugin_deserialise<'de>(
deserializer: &mut dyn $crate::erased_serde::Deserializer<'de>,
) -> Result<
::std::mem::ManuallyDrop<$crate::export::UnsafeReporterPlugin>,
$crate::erased_serde::Error,
> {
#[allow(clippy::enum_variant_names)]
#[derive($crate::serde::Deserialize)]
#[serde(crate = "::necsim_plugins_core::serde")]
enum Reporters {
$($name($plugin)),*
}
$crate::erased_serde::deserialize::<Reporters>(deserializer).map(|reporter| {
match reporter {
$(Reporters::$name(reporter) => reporter.into()),*
}
}).map(::std::mem::ManuallyDrop::new)
}
$(impl $crate::export::SerializeableReporter for $plugin {
fn reporter_name(&self) -> &'static str {
stringify!($name)
}
})*
#[doc(hidden)]
extern "C" fn __necsim_reporter_plugin_library_path() -> Option<::std::path::PathBuf> {
::necsim_plugins_core::process_path::get_dylib_path()
}
#[doc(hidden)]
extern "C" fn __necsim_reporter_plugin_drop(
plugin: ::std::mem::ManuallyDrop<$crate::export::UnsafeReporterPlugin>,
) {
::std::mem::drop(::std::mem::ManuallyDrop::into_inner(plugin))
}
#[doc(hidden)]
#[no_mangle]
pub static NECSIM_REPORTER_PLUGIN_DECLARATION: $crate::export::ReporterPluginDeclaration =
$crate::export::ReporterPluginDeclaration {
rustc_version: $crate::RUSTC_VERSION,
core_version: $crate::CORE_VERSION,
init: __necsim_reporter_plugin_init,
deserialise: __necsim_reporter_plugin_deserialise,
library_path: __necsim_reporter_plugin_library_path,
drop: __necsim_reporter_plugin_drop,
};
};
}
pub enum Reporters<'r> {
DynReporter(&'r DynReporterPlugin),
}
impl<'r> serde::Serialize for Reporters<'r> {
fn serialize<S: serde::Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
struct Reporter<'r>(&'r DynReporterPlugin);
impl<'r> serde::Serialize for Reporter<'r> {
fn serialize<S: serde::Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
erased_serde::serialize(self.0, serializer)
}
}
let Self::DynReporter(reporter) = self;
serializer.serialize_newtype_variant(
"Reporters",
0,
reporter.reporter_name(),
&Reporter(*reporter),
)
}
}