#[macro_export]
macro_rules! export_trait {
($func:path) => {
#[no_mangle]
pub unsafe extern "C" fn trait_call(
json_ptr: *const u8,
json_len: usize,
out_len: *mut usize,
) -> *mut u8 {
*out_len = 0;
if json_ptr.is_null() || json_len == 0 {
let result = $func(&[]);
let result_bytes = serde_json::to_vec(&result).unwrap_or_default();
let len = result_bytes.len();
let ptr = result_bytes.as_ptr() as *mut u8;
std::mem::forget(result_bytes);
*out_len = len;
return ptr;
}
let bytes = std::slice::from_raw_parts(json_ptr, json_len);
let args: Vec<serde_json::Value> = match serde_json::from_slice(bytes) {
Ok(v) => v,
Err(_) => {
let err = serde_json::json!({"error": "invalid JSON args"});
let err_bytes = serde_json::to_vec(&err).unwrap_or_default();
let len = err_bytes.len();
let ptr = err_bytes.as_ptr() as *mut u8;
std::mem::forget(err_bytes);
*out_len = len;
return ptr;
}
};
let result = $func(&args);
let result_bytes = serde_json::to_vec(&result).unwrap_or_default();
let len = result_bytes.len();
let ptr = result_bytes.as_ptr() as *mut u8;
std::mem::forget(result_bytes);
*out_len = len;
ptr
}
#[no_mangle]
pub unsafe extern "C" fn trait_free(ptr: *mut u8, len: usize) {
if !ptr.is_null() && len > 0 {
drop(Vec::from_raw_parts(ptr, len, len));
}
}
};
}
#[cfg(kernel)]
pub fn plugin_api(args: &[serde_json::Value]) -> serde_json::Value {
let _ = args;
let plugins = match crate::dylib_loader::LOADER.get() {
Some(loader) => {
let list = loader.list();
serde_json::json!(list)
}
None => serde_json::json!([]),
};
serde_json::json!({
"abi": {
"version": 1,
"entry": "trait_call(json_ptr: *const u8, json_len: usize, out_len: *mut usize) -> *mut u8",
"free": "trait_free(ptr: *mut u8, len: usize)",
"convention": "C",
"format": "JSON bytes in, JSON bytes out"
},
"installed_plugins": plugins,
"plugin_count": plugins.as_array().map(|a| a.len()).unwrap_or(0)
})
}