use crate::cglue::*;
use cglue::trait_group::c_void;
use std::prelude::v1::*;
pub mod args;
#[doc(hidden)]
pub use args::{ArgDescriptor, Args, ArgsValidator};
pub mod plugin_analyzer;
pub mod inventory;
pub use inventory::Inventory;
pub mod builder;
pub use builder::*;
pub type OptionVoid = Option<&'static mut c_void>;
pub type LibArc = CArc<c_void>;
pub mod connector;
pub use connector::{
cglue_connectorinstance::*, ConnectorArgs, ConnectorDescriptor, ConnectorMiddlewareArgs,
LoadableConnector,
};
pub type ConnectorInputArg = <LoadableConnector as Loadable>::InputArg;
pub mod os;
pub use os::{
cglue_intoprocessinstance::*, cglue_osinstance::*, cglue_processinstance::*,
IntoProcessInstanceArcBox, LoadableOs, MuOsInstanceArcBox, OsArgs, OsDescriptor,
OsInstanceArcBox, ProcessInstanceArcBox,
};
pub type OsInputArg = <LoadableOs as Loadable>::InputArg;
pub mod logger;
pub use logger::*;
pub(crate) mod util;
pub use util::*;
use crate::error::{Result, *};
use log::warn;
use std::mem::MaybeUninit;
use abi_stable::{type_layout::TypeLayout, StableAbi};
use libloading::Library;
use once_cell::sync::OnceCell;
use self::plugin_analyzer::PluginKind;
pub const MEMFLOW_PLUGIN_VERSION: i32 = 1;
pub type HelpCallback<'a> = OpaqueCallback<'a, ReprCString>;
pub struct LibContext {
lib: Library,
logger: OnceCell<Box<PluginLogger>>,
}
impl From<Library> for LibContext {
fn from(lib: Library) -> Self {
Self {
lib,
logger: Default::default(),
}
}
}
impl LibContext {
pub unsafe fn get_logger(&self) -> &'static PluginLogger {
(&**self.logger.get_or_init(|| Box::new(PluginLogger::new())) as *const PluginLogger)
.as_ref()
.unwrap()
}
pub fn try_get_logger(&self) -> Option<&PluginLogger> {
self.logger.get().map(|l| &**l)
}
}
#[repr(C)]
#[derive(Clone, Debug)]
#[cfg_attr(feature = "serde", derive(::serde::Serialize, ::serde::Deserialize))]
pub struct TargetInfo {
pub name: ReprCString,
}
pub type TargetCallback<'a> = OpaqueCallback<'a, TargetInfo>;
#[repr(C)]
pub struct PluginDescriptor<T: Loadable> {
pub plugin_version: i32,
pub accept_input: bool,
pub input_layout: &'static TypeLayout,
pub output_layout: &'static TypeLayout,
pub name: CSliceRef<'static, u8>,
pub version: CSliceRef<'static, u8>,
pub description: CSliceRef<'static, u8>,
pub help_callback: Option<extern "C" fn(callback: HelpCallback) -> ()>,
pub target_list_callback: Option<extern "C" fn(callback: TargetCallback) -> i32>,
pub create: CreateFn<T>,
}
#[allow(improper_ctypes_definitions)]
pub type CreateFn<T> = extern "C" fn(
Option<&<T as Loadable>::ArgsType>,
<T as Loadable>::CInputArg,
lib: LibArc,
logger: Option<&'static PluginLogger>,
&mut MaybeUninit<<T as Loadable>::Instance>,
) -> i32;
pub trait Loadable: Sized {
type Instance: StableAbi;
type InputArg;
type CInputArg: StableAbi;
type ArgsType;
fn ident(&self) -> &str;
fn plugin_kind() -> PluginKind;
fn export_prefix() -> &'static str;
fn new(descriptor: PluginDescriptor<Self>) -> Self;
fn from_instance(instance: &CArc<LibContext>, export_name: &str) -> Result<Self> {
let raw_descriptor = unsafe {
instance
.as_ref()
.ok_or(Error(ErrorOrigin::Inventory, ErrorKind::Uninitialized))?
.lib
.get::<*mut PluginDescriptor<Self>>(format!("{}\0", export_name).as_bytes())
.map_err(|_| Error(ErrorOrigin::Inventory, ErrorKind::MemflowExportsNotFound))?
.read()
};
if raw_descriptor.plugin_version != MEMFLOW_PLUGIN_VERSION {
warn!(
"{} has a different version. version {} required, found {}.",
export_name, MEMFLOW_PLUGIN_VERSION, raw_descriptor.plugin_version
);
return Err(Error(ErrorOrigin::Inventory, ErrorKind::VersionMismatch));
}
if VerifyLayout::check::<Self::CInputArg>(Some(raw_descriptor.input_layout))
.and(VerifyLayout::check::<Self::Instance>(Some(
raw_descriptor.output_layout,
)))
.is_valid_strict()
{
Ok(Self::new(raw_descriptor))
} else {
warn!("{} has a different abi version.", export_name,);
Err(Error(ErrorOrigin::Inventory, ErrorKind::VersionMismatch))
}
}
fn help(&self) -> Result<String>;
fn target_list(&self) -> Result<Vec<TargetInfo>>;
fn instantiate(
&self,
library: CArc<LibContext>,
input: Self::InputArg,
args: Option<&Self::ArgsType>,
) -> Result<Self::Instance>;
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
pub fn ensure_stable_abi() {
assert_eq!(MEMFLOW_PLUGIN_VERSION, 1)
}
}