Skip to main content

reifydb_sdk/transform/
exports.rs

1// SPDX-License-Identifier: Apache-2.0
2// Copyright (c) 2025 ReifyDB
3
4use std::{collections::HashMap, ffi::c_void, ptr, slice};
5
6use postcard::from_bytes;
7use reifydb_abi::{
8	constants::CURRENT_API,
9	data::buffer::BufferFFI,
10	transform::{descriptor::TransformDescriptorFFI, types::TRANSFORM_MAGIC},
11};
12use reifydb_type::value::Value;
13
14use crate::transform::{
15	FFITransformWithMetadata,
16	wrapper::{TransformWrapper, create_transform_vtable},
17};
18
19fn str_to_buffer(s: &'static str) -> BufferFFI {
20	BufferFFI {
21		ptr: s.as_ptr(),
22		len: s.len(),
23		cap: s.len(),
24	}
25}
26
27pub fn create_transform_descriptor<T: FFITransformWithMetadata>() -> TransformDescriptorFFI {
28	TransformDescriptorFFI {
29		api: CURRENT_API,
30		name: str_to_buffer(T::NAME),
31		version: str_to_buffer(T::VERSION),
32		description: str_to_buffer(T::DESCRIPTION),
33		vtable: create_transform_vtable::<T>(),
34	}
35}
36
37/// # Safety
38///
39/// - `config_ptr` must either be null or point to `config_len` valid bytes of postcard-encoded config.
40pub unsafe extern "C" fn create_transform_instance<T: FFITransformWithMetadata>(
41	config_ptr: *const u8,
42	config_len: usize,
43) -> *mut c_void {
44	let config = if config_ptr.is_null() || config_len == 0 {
45		HashMap::new()
46	} else {
47		let config_bytes = unsafe { slice::from_raw_parts(config_ptr, config_len) };
48
49		match from_bytes::<HashMap<String, Value>>(config_bytes) {
50			Ok(decoded_config) => decoded_config,
51			Err(e) => {
52				panic!("Failed to deserialize transform config: {}", e);
53			}
54		}
55	};
56
57	let transform = match T::new(&config) {
58		Ok(t) => t,
59		Err(e) => {
60			eprintln!("Failed to create transform: {}", e);
61			return ptr::null_mut();
62		}
63	};
64
65	let wrapper = Box::new(TransformWrapper::new(transform));
66	Box::into_raw(wrapper) as *mut c_void
67}
68
69pub extern "C" fn transform_magic() -> u32 {
70	TRANSFORM_MAGIC
71}