use std::ffi::CStr;
use crate::memgraph::*;
#[double]
use crate::mgp::ffi;
use mockall_double::double;
#[macro_export]
macro_rules! define_procedure {
($c_name:ident, $rs_func:expr) => {
#[no_mangle]
extern "C" fn $c_name(
args: *const mgp_list,
graph: *const mgp_graph,
result: *mut mgp_result,
memory: *mut mgp_memory,
) {
let prev_hook = panic::take_hook();
panic::set_hook(Box::new(|_| { }));
let procedure_result = panic::catch_unwind(|| {
let memgraph = Memgraph::new(args, graph, result, memory, std::ptr::null_mut());
match $rs_func(&memgraph) {
Ok(_) => (),
Err(e) => {
println!("{}", e);
let msg = e.to_string();
println!("{}", msg);
let c_msg =
CString::new(msg).expect("Unable to create Memgraph error message!");
set_memgraph_error_msg(&c_msg, &memgraph);
}
}
});
panic::set_hook(prev_hook);
match procedure_result {
Ok(_) => {}
Err(e) => {
println!("Procedure panic!");
match e.downcast::<&str>() {
Ok(panic_msg) => {
println!("{}", panic_msg);
}
Err(_) => {
println!("Unknown type of panic!.");
}
}
println!("{:?}", Backtrace::new());
}
}
}
};
}
#[macro_export]
macro_rules! init_module {
($init_func:expr) => {
#[no_mangle]
pub extern "C" fn mgp_init_module(
module: *mut mgp_module,
memory: *mut mgp_memory,
) -> c_int {
let prev_hook = panic::take_hook();
panic::set_hook(Box::new(|_| { }));
let result = panic::catch_unwind(|| {
let memgraph = Memgraph::new(
std::ptr::null_mut(),
std::ptr::null_mut(),
std::ptr::null_mut(),
memory,
module,
);
$init_func(&memgraph)
});
panic::set_hook(prev_hook);
match result {
Ok(_) => 0,
Err(_) => 1,
}
}
};
}
#[macro_export]
macro_rules! close_module {
($close_func:expr) => {
#[no_mangle]
pub extern "C" fn mgp_shutdown_module() -> c_int {
let prev_hook = panic::take_hook();
panic::set_hook(Box::new(|_| { }));
let result = panic::catch_unwind(|| $close_func());
panic::set_hook(prev_hook);
match result {
Ok(_) => 0,
Err(_) => 1,
}
}
};
}
pub enum FieldType {
Any,
Bool,
Number,
Int,
Double,
String,
Map,
Vertex,
Edge,
Path,
Nullable,
List,
}
pub struct ResultFieldType<'a> {
pub name: &'a CStr,
pub types: &'a [FieldType],
}
#[macro_export]
macro_rules! define_type {
($name:literal, $($types:expr),+) => {
ResultFieldType {
name: &c_str!($name),
types: &[$($types),+],
}
};
}
pub fn set_memgraph_error_msg(msg: &CStr, memgraph: &Memgraph) {
unsafe {
let status = ffi::mgp_result_set_error_msg(memgraph.result(), msg.as_ptr());
if status == 0 {
panic!("Unable to pass error message to the Memgraph engine.");
}
}
}
#[cfg(test)]
mod tests {
use c_str_macro::c_str;
use serial_test::serial;
use super::*;
use crate::mgp::mock_ffi::*;
use crate::{mock_mgp_once, with_dummy};
#[test]
#[serial]
fn test_set_error_msg() {
mock_mgp_once!(mgp_result_set_error_msg_context, |_, _| 1);
with_dummy!(|memgraph: &Memgraph| {
set_memgraph_error_msg(c_str!("test_error"), &memgraph);
});
}
}