reifydb_sdk/procedure/
wrapper.rs1use std::{
5 ffi::c_void,
6 panic::{AssertUnwindSafe, catch_unwind},
7 process::abort,
8 slice,
9};
10
11use postcard::from_bytes;
12use reifydb_abi::{context::context::ContextFFI, procedure::vtable::ProcedureVTableFFI};
13use reifydb_type::params::Params;
14use tracing::error;
15
16use crate::procedure::{FFIProcedure, FFIProcedureContext};
17
18pub struct ProcedureWrapper<T: FFIProcedure> {
19 procedure: T,
20}
21
22impl<T: FFIProcedure> ProcedureWrapper<T> {
23 pub fn new(procedure: T) -> Self {
24 Self {
25 procedure,
26 }
27 }
28
29 pub fn from_ptr(ptr: *mut c_void) -> &'static mut Self {
30 unsafe { &mut *(ptr as *mut Self) }
31 }
32}
33
34pub unsafe extern "C" fn ffi_procedure_call<T: FFIProcedure>(
39 instance: *mut c_void,
40 ctx: *mut ContextFFI,
41 params_ptr: *const u8,
42 params_len: usize,
43) -> i32 {
44 let result = catch_unwind(AssertUnwindSafe(|| {
45 let wrapper = ProcedureWrapper::<T>::from_ptr(instance);
46
47 let params: Params = if params_ptr.is_null() || params_len == 0 {
48 Params::None
49 } else {
50 let bytes = unsafe { slice::from_raw_parts(params_ptr, params_len) };
51 match from_bytes(bytes) {
52 Ok(p) => p,
53 Err(e) => {
54 error!(?e, "Failed to deserialize procedure params");
55 return -2;
56 }
57 }
58 };
59
60 let mut pctx = FFIProcedureContext::new(ctx);
61
62 match wrapper.procedure.call(&mut pctx, params) {
63 Ok(()) => 0,
64 Err(e) => {
65 error!(?e, "Procedure call failed");
66 -2
67 }
68 }
69 }));
70
71 let code = result.unwrap_or_else(|e| {
72 error!(?e, "Panic in ffi_procedure_call");
73 -99
74 });
75 if code < 0 {
76 error!(code, "ffi_procedure_call failed - aborting");
77 abort();
78 }
79 code
80}
81
82pub unsafe extern "C" fn ffi_procedure_destroy<T: FFIProcedure>(instance: *mut c_void) {
86 if instance.is_null() {
87 return;
88 }
89
90 let result = catch_unwind(AssertUnwindSafe(|| unsafe {
91 let _wrapper = Box::from_raw(instance as *mut ProcedureWrapper<T>);
92 }));
93
94 if let Err(e) = result {
95 error!(?e, "Panic in ffi_procedure_destroy - aborting");
96 abort();
97 }
98}
99
100pub fn create_procedure_vtable<T: FFIProcedure>() -> ProcedureVTableFFI {
101 ProcedureVTableFFI {
102 call: ffi_procedure_call::<T>,
103 destroy: ffi_procedure_destroy::<T>,
104 }
105}