Skip to main content

export_module

Macro export_module 

Source
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), where arities is a &'static [u8] of accepted argument counts and function is a RustPluginFn.
  • A class: class("Name") { (method, arities, fun), ... }, optionally followed by drop: drop_fn, and/or traverse: traverse_fn, (in that order). Method arities count self; the receiver arrives as args[0].
  • A value: value("name", creator), where creator is a RustPluginValueFn building 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).