#[doc(hidden)]
#[macro_export]
macro_rules! plugin_registry {
($vis:vis $registry:ident: $Type:ty) => {
#[used]
#[allow(non_upper_case_globals)]
#[doc(hidden)]
$vis static $registry: std::sync::Mutex<Vec<$Type>>
= std::sync::Mutex::new(Vec::new());
};
}
#[doc(hidden)]
#[macro_export]
macro_rules! plugin_execute_pre_main {
($body:expr_2021) => {
const _: () = {
#[allow(non_upper_case_globals)]
#[used]
#[cfg_attr(target_os = "windows", unsafe(link_section = ".CRT$XCU"))]
#[cfg_attr(target_os = "ios", unsafe(link_section = "__DATA,__mod_init_func"))]
#[cfg_attr(target_os = "macos", unsafe(link_section = "__DATA,__mod_init_func"))]
#[cfg_attr(target_os = "android", unsafe(link_section = ".init_array"))]
#[cfg_attr(target_os = "dragonfly", unsafe(link_section = ".init_array"))]
#[cfg_attr(target_os = "freebsd", unsafe(link_section = ".init_array"))]
#[cfg_attr(target_os = "linux", unsafe(link_section = ".init_array"))]
#[cfg_attr(target_os = "netbsd", unsafe(link_section = ".init_array"))]
#[cfg_attr(target_os = "openbsd", unsafe(link_section = ".init_array"))]
#[cfg_attr(
all(target_family = "wasm", target_os = "emscripten"),
unsafe(link_section = ".init_array")
)]
static __init: extern "C" fn() = {
#[cfg_attr(target_os = "android", unsafe(link_section = ".text.startup"))]
#[cfg_attr(target_os = "linux", unsafe(link_section = ".text.startup"))]
extern "C" fn __inner_init() {
$body
}
__inner_init
};
};
};
}
#[doc(hidden)]
#[macro_export]
macro_rules! plugin_add {
( $registry:path; $plugin:expr_2021 ) => {
$crate::plugin_execute_pre_main!({
$registry.lock().unwrap().push($plugin);
});
};
}
#[doc(hidden)]
#[macro_export]
macro_rules! plugin_foreach_inner {
( $registry:ident; $closure:expr_2021; $( $path_tt:tt )* ) => {
let guard = $( $path_tt )* $registry
.lock()
.unwrap();
for e in guard.iter() {
#[allow(clippy::redundant_closure_call)]
$closure(e);
}
};
}
#[doc(hidden)]
#[macro_export]
macro_rules! plugin_foreach {
( $registry:ident; $closure:expr_2021 ) => {
$crate::plugin_foreach_inner!($registry; $closure; );
};
( $registry:ident in $path:path; $closure:expr_2021 ) => {
$crate::plugin_foreach_inner!($registry; $closure; $path ::);
};
}
#[cfg(test)] #[cfg_attr(published_docs, doc(cfg(test)))]
mod tests {
use std::collections::HashSet;
plugin_registry!(V: &'static str);
plugin_add!(V; "three");
plugin_add!(V; "four");
plugin_add!(V; "one");
plugin_add!(V; "two");
#[test]
#[cfg_attr(
target_family = "wasm",
ignore = "Requires a plugin implementation for Wasm"
)]
fn plugin_registry() {
let expected = HashSet::from(["one", "two", "three", "four"]);
let mut actual = HashSet::new();
plugin_foreach!(V; |e: &'static str| {
actual.insert(e);
});
assert_eq!(actual, expected);
}
}