Skip to main content

reifydb_sdk/transform/
wrapper.rs

1// SPDX-License-Identifier: Apache-2.0
2// Copyright (c) 2026 ReifyDB
3
4use std::{
5	ffi::c_void,
6	panic::{AssertUnwindSafe, catch_unwind},
7	process::abort,
8};
9
10use reifydb_abi::{context::context::ContextFFI, data::column::ColumnsFFI, transform::vtable::TransformVTableFFI};
11use tracing::error;
12
13use crate::{
14	operator::change::BorrowedColumns,
15	transform::{FFITransform, context::FFITransformContext},
16};
17
18pub struct TransformWrapper<T: FFITransform> {
19	transform: T,
20}
21
22impl<T: FFITransform> TransformWrapper<T> {
23	pub fn new(transform: T) -> Self {
24		Self {
25			transform,
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
34/// # Safety
35///
36/// - `instance` must be a valid pointer to a `TransformWrapper<T>`.
37/// - `ctx` must point to a valid `ContextFFI`.
38/// - `input` must point to a valid `ColumnsFFI`.
39pub unsafe extern "C" fn ffi_transform<T: FFITransform>(
40	instance: *mut c_void,
41	ctx: *mut ContextFFI,
42	input: *const ColumnsFFI,
43) -> i32 {
44	let result = catch_unwind(AssertUnwindSafe(|| {
45		let wrapper = TransformWrapper::<T>::from_ptr(instance);
46
47		let borrowed_input = unsafe { BorrowedColumns::from_ffi(input) };
48		let mut tctx = FFITransformContext::new(ctx);
49
50		match wrapper.transform.transform(&mut tctx, borrowed_input) {
51			Ok(()) => 0,
52			Err(e) => {
53				error!(?e, "Transform failed");
54				-2
55			}
56		}
57	}));
58
59	let code = result.unwrap_or_else(|e| {
60		error!(?e, "Panic in ffi_transform");
61		-99
62	});
63	if code < 0 {
64		error!(code, "ffi_transform failed - aborting");
65		abort();
66	}
67	code
68}
69
70/// # Safety
71///
72/// - `instance` must be a valid pointer to a `TransformWrapper<T>`, or null.
73pub unsafe extern "C" fn ffi_transform_destroy<T: FFITransform>(instance: *mut c_void) {
74	if instance.is_null() {
75		return;
76	}
77
78	let result = catch_unwind(AssertUnwindSafe(|| unsafe {
79		let _wrapper = Box::from_raw(instance as *mut TransformWrapper<T>);
80	}));
81
82	if let Err(e) = result {
83		error!(?e, "Panic in ffi_transform_destroy - aborting");
84		abort();
85	}
86}
87
88pub fn create_transform_vtable<T: FFITransform>() -> TransformVTableFFI {
89	TransformVTableFFI {
90		transform: ffi_transform::<T>,
91		destroy: ffi_transform_destroy::<T>,
92	}
93}