use crate::*;
use std::slice;
unsafe fn read_bytes(ptr: *const u8, len: usize) -> Vec<u8> {
if ptr.is_null() || len == 0 {
return Vec::new();
}
slice::from_raw_parts(ptr, len).to_vec()
}
fn write_result(data: &[u8]) -> *mut u8 {
let total_len = 4 + data.len();
let mut buffer = Vec::with_capacity(total_len);
let len_bytes = (data.len() as u32).to_le_bytes();
buffer.extend_from_slice(&len_bytes);
buffer.extend_from_slice(data);
let ptr = buffer.as_mut_ptr();
std::mem::forget(buffer);
ptr
}
pub fn ffi_schema<F>(schema_fn: F) -> *mut u8
where
F: Fn() -> String,
{
let schema_content = schema_fn();
write_result(schema_content.as_bytes())
}
pub unsafe fn ffi_validate_config<F>(
level_ptr: *const u8,
level_len: usize,
config_ptr: *const u8,
config_len: usize,
validate_fn: F,
) -> *mut u8
where
F: Fn(ConfigLevel, JSON, &Utils) -> Vec<ValidationError>,
{
let level_bytes = read_bytes(level_ptr, level_len);
let config_bytes = read_bytes(config_ptr, config_len);
let level: ConfigLevel = match serde_json::from_slice(&level_bytes) {
Ok(l) => l,
Err(e) => {
eprintln!("Failed to deserialize ConfigLevel: {}", e);
return write_result(b"[]");
}
};
let config: JSON = match serde_json::from_slice(&config_bytes) {
Ok(c) => c,
Err(e) => {
eprintln!("Failed to deserialize config: {}", e);
return write_result(b"[]");
}
};
let utils = Utils;
let errors = validate_fn(level, config, &utils);
let result_json = match serde_json::to_vec(&errors) {
Ok(json) => json,
Err(e) => {
eprintln!("Failed to serialize validation errors: {}", e);
return write_result(b"[]");
}
};
write_result(&result_json)
}
pub unsafe fn ffi_build<F>(
schema_ptr: *const u8,
schema_len: usize,
config_ptr: *const u8,
config_len: usize,
build_fn: F,
) -> *mut u8
where
F: Fn(Schema, JSON, &Utils) -> Vec<OutputFile>,
{
let schema_bytes = read_bytes(schema_ptr, schema_len);
let config_bytes = read_bytes(config_ptr, config_len);
let schema: Schema = match serde_json::from_slice(&schema_bytes) {
Ok(s) => s,
Err(e) => {
eprintln!("Failed to deserialize Schema: {}", e);
return write_result(b"[]");
}
};
let config: JSON = match serde_json::from_slice(&config_bytes) {
Ok(c) => c,
Err(e) => {
eprintln!("Failed to deserialize config: {}", e);
return write_result(b"[]");
}
};
let utils = Utils;
let files = build_fn(schema, config, &utils);
let result_json = match serde_json::to_vec(&files) {
Ok(json) => json,
Err(e) => {
eprintln!("Failed to serialize output files: {}", e);
return write_result(b"[]");
}
};
write_result(&result_json)
}
pub unsafe fn ffi_migrate<F>(
schema_ptr: *const u8,
schema_len: usize,
deltas_ptr: *const u8,
deltas_len: usize,
config_ptr: *const u8,
config_len: usize,
migrate_fn: F,
) -> *mut u8
where
F: Fn(Schema, Vec<Delta>, JSON, &Utils) -> Vec<OutputFile>,
{
let schema_bytes = read_bytes(schema_ptr, schema_len);
let deltas_bytes = read_bytes(deltas_ptr, deltas_len);
let config_bytes = read_bytes(config_ptr, config_len);
let schema: Schema = match serde_json::from_slice(&schema_bytes) {
Ok(s) => s,
Err(e) => {
eprintln!("Failed to deserialize Schema: {}", e);
return write_result(b"[]");
}
};
let deltas: Vec<Delta> = match serde_json::from_slice(&deltas_bytes) {
Ok(d) => d,
Err(e) => {
eprintln!("Failed to deserialize deltas: {}", e);
return write_result(b"[]");
}
};
let config: JSON = match serde_json::from_slice(&config_bytes) {
Ok(c) => c,
Err(e) => {
eprintln!("Failed to deserialize config: {}", e);
return write_result(b"[]");
}
};
let utils = Utils;
let files = migrate_fn(schema, deltas, config, &utils);
let result_json = match serde_json::to_vec(&files) {
Ok(json) => json,
Err(e) => {
eprintln!("Failed to serialize migration files: {}", e);
return write_result(b"[]");
}
};
write_result(&result_json)
}
#[no_mangle]
pub extern "C" fn _alloc(size: usize) -> *mut u8 {
let mut buf = Vec::with_capacity(size);
let ptr = buf.as_mut_ptr();
std::mem::forget(buf);
ptr
}
#[no_mangle]
pub unsafe extern "C" fn _dealloc(ptr: *mut u8, size: usize) {
if !ptr.is_null() && size > 0 {
let _ = Vec::from_raw_parts(ptr, 0, size);
}
}
#[macro_export]
macro_rules! export_schema {
($func:expr) => {
#[no_mangle]
pub extern "C" fn _schema() -> *mut u8 {
$crate::ffi::ffi_schema($func)
}
};
}
#[macro_export]
macro_rules! export_validate_config {
($func:expr) => {
#[no_mangle]
pub extern "C" fn _validate_config(
level_ptr: *const u8,
level_len: usize,
config_ptr: *const u8,
config_len: usize,
) -> *mut u8 {
unsafe {
$crate::ffi::ffi_validate_config(
level_ptr,
level_len,
config_ptr,
config_len,
$func,
)
}
}
};
}
#[macro_export]
macro_rules! export_build {
($func:expr) => {
#[no_mangle]
pub extern "C" fn _build(
schema_ptr: *const u8,
schema_len: usize,
config_ptr: *const u8,
config_len: usize,
) -> *mut u8 {
unsafe {
$crate::ffi::ffi_build(
schema_ptr,
schema_len,
config_ptr,
config_len,
$func,
)
}
}
};
}
#[macro_export]
macro_rules! export_migrate {
($func:expr) => {
#[no_mangle]
pub extern "C" fn _migrate(
schema_ptr: *const u8,
schema_len: usize,
deltas_ptr: *const u8,
deltas_len: usize,
config_ptr: *const u8,
config_len: usize,
) -> *mut u8 {
unsafe {
$crate::ffi::ffi_migrate(
schema_ptr,
schema_len,
deltas_ptr,
deltas_len,
config_ptr,
config_len,
$func,
)
}
}
};
}