use std::{
ffi::c_void,
panic::{AssertUnwindSafe, catch_unwind},
process::abort,
};
use tracing::error;
use crate::{
common::extern_c::wire::columns::ExternCColumns,
flow::operator::change::BorrowedColumns,
transform::extern_c::{
binding::{context::ExternCTransformContext, transform::ExternCTransform},
wire::{context::ExternCContextRaw, vtable::ExternCTransformVTable},
},
};
pub struct TransformWrapper<T: ExternCTransform> {
transform: T,
}
impl<T: ExternCTransform> TransformWrapper<T> {
pub fn new(transform: T) -> Self {
Self {
transform,
}
}
pub fn from_ptr(ptr: *mut c_void) -> &'static mut Self {
unsafe { &mut *(ptr as *mut Self) }
}
}
pub unsafe extern "C" fn extern_c_transform<T: ExternCTransform>(
instance: *mut c_void,
ctx: *mut ExternCContextRaw,
input: *const ExternCColumns,
) -> i32 {
let result = catch_unwind(AssertUnwindSafe(|| {
let wrapper = TransformWrapper::<T>::from_ptr(instance);
let borrowed_input = unsafe { BorrowedColumns::from_extern_c(input) };
let mut tctx = ExternCTransformContext::new(ctx);
match wrapper.transform.transform(&mut tctx, borrowed_input) {
Ok(()) => 0,
Err(e) => {
error!(?e, "Transform failed");
-2
}
}
}));
let code = result.unwrap_or_else(|e| {
error!(?e, "Panic in extern_c_transform");
-99
});
if code < 0 {
error!(code, "extern_c_transform failed - aborting");
abort();
}
code
}
pub unsafe extern "C" fn extern_c_transform_destroy<T: ExternCTransform>(instance: *mut c_void) {
if instance.is_null() {
return;
}
let result = catch_unwind(AssertUnwindSafe(|| unsafe {
let _wrapper = Box::from_raw(instance as *mut TransformWrapper<T>);
}));
if let Err(e) = result {
error!(?e, "Panic in extern_c_transform_destroy - aborting");
abort();
}
}
pub fn create_transform_vtable<T: ExternCTransform>() -> ExternCTransformVTable {
ExternCTransformVTable {
transform: extern_c_transform::<T>,
destroy: extern_c_transform_destroy::<T>,
}
}