extern crate fidius_core as fidius;
use fidius_macro::{plugin_impl, plugin_interface};
#[plugin_interface(version = 1, buffer = PluginAllocated)]
pub trait MultiArg: Send + Sync {
fn status(&self) -> String;
fn echo(&self, msg: String) -> String;
fn concat(&self, a: String, b: String) -> String;
fn add_three(&self, x: i64, y: i64, z: i64) -> i64;
}
pub struct MyMultiArg;
#[plugin_impl(MultiArg)]
impl MultiArg for MyMultiArg {
fn status(&self) -> String {
"ok".to_string()
}
fn echo(&self, msg: String) -> String {
format!("echo: {msg}")
}
fn concat(&self, a: String, b: String) -> String {
format!("{a}{b}")
}
fn add_three(&self, x: i64, y: i64, z: i64) -> i64 {
x + y + z
}
}
fidius_core::fidius_plugin_registry!();
fn get_registry() -> &'static fidius_core::descriptor::PluginRegistry {
fidius_core::registry::get_registry()
}
unsafe fn call_vtable(
vtable: &__fidius_MultiArg::MultiArg_VTable,
index: usize,
input_bytes: &[u8],
free_buffer: Option<unsafe extern "C" fn(*mut u8, usize)>,
) -> (i32, Vec<u8>) {
let fns: [unsafe extern "C" fn(*const u8, u32, *mut *mut u8, *mut u32) -> i32; 4] =
[vtable.status, vtable.echo, vtable.concat, vtable.add_three];
let mut out_ptr: *mut u8 = std::ptr::null_mut();
let mut out_len: u32 = 0;
let status = unsafe {
(fns[index])(
input_bytes.as_ptr(),
input_bytes.len() as u32,
&mut out_ptr,
&mut out_len,
)
};
let output = if !out_ptr.is_null() && out_len > 0 {
let slice = unsafe { std::slice::from_raw_parts(out_ptr, out_len as usize) };
let v = slice.to_vec();
if let Some(free) = free_buffer {
unsafe { free(out_ptr, out_len as usize) };
}
v
} else {
vec![]
};
(status, output)
}
#[test]
fn zero_args_status() {
let reg = get_registry();
let desc = unsafe { &**reg.descriptors };
let vtable = unsafe { &*(desc.vtable as *const __fidius_MultiArg::MultiArg_VTable) };
let input_bytes = fidius_core::wire::serialize(&()).unwrap();
let (status, output) = unsafe { call_vtable(vtable, 0, &input_bytes, desc.free_buffer) };
assert_eq!(status, 0, "status() should return STATUS_OK");
let result: String = fidius_core::wire::deserialize(&output).unwrap();
assert_eq!(result, "ok");
}
#[test]
fn one_arg_echo() {
let reg = get_registry();
let desc = unsafe { &**reg.descriptors };
let vtable = unsafe { &*(desc.vtable as *const __fidius_MultiArg::MultiArg_VTable) };
let input_bytes = fidius_core::wire::serialize(&("hello".to_string(),)).unwrap();
let (status, output) = unsafe { call_vtable(vtable, 1, &input_bytes, desc.free_buffer) };
assert_eq!(status, 0, "echo() should return STATUS_OK");
let result: String = fidius_core::wire::deserialize(&output).unwrap();
assert_eq!(result, "echo: hello");
}
#[test]
fn two_args_concat() {
let reg = get_registry();
let desc = unsafe { &**reg.descriptors };
let vtable = unsafe { &*(desc.vtable as *const __fidius_MultiArg::MultiArg_VTable) };
let input_bytes =
fidius_core::wire::serialize(&("foo".to_string(), "bar".to_string())).unwrap();
let (status, output) = unsafe { call_vtable(vtable, 2, &input_bytes, desc.free_buffer) };
assert_eq!(status, 0, "concat() should return STATUS_OK");
let result: String = fidius_core::wire::deserialize(&output).unwrap();
assert_eq!(result, "foobar");
}
#[test]
fn three_args_add() {
let reg = get_registry();
let desc = unsafe { &**reg.descriptors };
let vtable = unsafe { &*(desc.vtable as *const __fidius_MultiArg::MultiArg_VTable) };
let input_bytes = fidius_core::wire::serialize(&(10i64, 20i64, 30i64)).unwrap();
let (status, output) = unsafe { call_vtable(vtable, 3, &input_bytes, desc.free_buffer) };
assert_eq!(status, 0, "add_three() should return STATUS_OK");
let result: i64 = fidius_core::wire::deserialize(&output).unwrap();
assert_eq!(result, 60);
}
#[test]
fn method_indices_correct() {
assert_eq!(__fidius_MultiArg::METHOD_STATUS, 0);
assert_eq!(__fidius_MultiArg::METHOD_ECHO, 1);
assert_eq!(__fidius_MultiArg::METHOD_CONCAT, 2);
assert_eq!(__fidius_MultiArg::METHOD_ADD_THREE, 3);
}