macro_rules! export_module {
[$($t:tt)*] => { ... };
}Expand description
Export the plugin’s functions and classes to the generic interpreter.
Takes a comma-separated list of entries, each either:
- A function:
(name, arities, function), wherearitiesis a&'static [u8]of accepted argument counts andfunctionis aRustPluginFn. - A class:
class("Name") { (method, arities, fun), ... }, optionally followed bydrop: drop_fn,and/ortraverse: traverse_fn,(in that order). Methodaritiescountself; the receiver arrives asargs[0]. - A value:
value("name", creator), wherecreatoris aRustPluginValueFnbuilding one module constant at import time.
ⓘ
use generic_lang_api::{GenericValue, Host, PluginError, PluginVisitFn};
fn add(host: &mut Host, args: &[GenericValue]) -> Result<GenericValue, PluginError> {
let (Some(a), Some(b)) = (host.as_int(args[0]), host.as_int(args[1])) else {
return Err(host.type_error("add expects two integers"));
};
Ok(host.make_int(a + b))
}
struct CounterState { value: i64 }
// Methods take the receiver (`self`) as a separate parameter; `args` are the
// remaining arguments, and arities exclude the receiver.
fn counter_init(host: &mut Host, this: GenericValue, _args: &[GenericValue])
-> Result<GenericValue, PluginError> {
let ptr = Box::into_raw(Box::new(CounterState { value: 0 })).cast();
host.set_opaque(this, ptr)?;
Ok(this) // like every __init__, return the receiver
}
extern "C" fn drop_counter(ptr: *mut core::ffi::c_void) {
if !ptr.is_null() { unsafe { drop(Box::from_raw(ptr.cast::<CounterState>())) }; }
}
generic_lang_api::export_module![
("add", &[2], add),
class("Counter") {
("__init__", &[0], counter_init), // no extra args beyond the receiver
drop: drop_counter,
},
];Expands to static descriptor tables (the same shape a C plugin declares by
hand) and the one symbol every plugin must export, generic_plugin_init,
plus a panic-safe extern "C" wrapper per function/method (a panicking
plugin call becomes a catchable generic exception instead of aborting the
whole interpreter process, which is what an unwind reaching an extern "C"
boundary does).