#![allow(dead_code)]
use std::ffi::c_char;
use std::sync::Arc;
use blazen_uniffi::persist::{
CheckpointStore as InnerCheckpointStore, WorkflowCheckpoint as InnerWorkflowCheckpoint,
};
use crate::error::BlazenError;
use crate::future::BlazenFuture;
use crate::persist_records::BlazenWorkflowCheckpoint;
use crate::runtime::runtime;
use crate::string::{alloc_cstring, cstr_to_str};
fn checkpoints_to_c_array(
items: Vec<InnerWorkflowCheckpoint>,
) -> (*mut *mut BlazenWorkflowCheckpoint, usize) {
let boxed: Box<[*mut BlazenWorkflowCheckpoint]> = items
.into_iter()
.map(|v| BlazenWorkflowCheckpoint::from(v).into_ptr())
.collect::<Vec<_>>()
.into_boxed_slice();
let len = boxed.len();
let raw = Box::into_raw(boxed);
(raw.cast::<*mut BlazenWorkflowCheckpoint>(), len)
}
fn strings_to_c_array(items: Vec<String>) -> (*mut *mut c_char, usize) {
let boxed: Box<[*mut c_char]> = items
.into_iter()
.map(|s| alloc_cstring(&s))
.collect::<Vec<_>>()
.into_boxed_slice();
let len = boxed.len();
let raw = Box::into_raw(boxed);
(raw.cast::<*mut c_char>(), len)
}
pub struct BlazenCheckpointStore(pub(crate) Arc<InnerCheckpointStore>);
impl BlazenCheckpointStore {
pub(crate) fn into_ptr(self) -> *mut BlazenCheckpointStore {
Box::into_raw(Box::new(self))
}
}
impl From<Arc<InnerCheckpointStore>> for BlazenCheckpointStore {
fn from(inner: Arc<InnerCheckpointStore>) -> Self {
Self(inner)
}
}
#[unsafe(no_mangle)]
pub unsafe extern "C" fn blazen_checkpoint_store_save_blocking(
store: *const BlazenCheckpointStore,
checkpoint: *mut BlazenWorkflowCheckpoint,
out_err: *mut *mut BlazenError,
) -> i32 {
if store.is_null() || checkpoint.is_null() {
if !checkpoint.is_null() {
drop(unsafe { Box::from_raw(checkpoint) });
}
return -2;
}
let store = unsafe { &*store };
let checkpoint = unsafe { Box::from_raw(checkpoint) };
let inner_checkpoint = checkpoint.0;
let store_inner = Arc::clone(&store.0);
let result = runtime().block_on(async move { store_inner.save(inner_checkpoint).await });
match result {
Ok(()) => 0,
Err(e) => {
if !out_err.is_null() {
unsafe {
*out_err = BlazenError::from(e).into_ptr();
}
}
-1
}
}
}
#[unsafe(no_mangle)]
pub unsafe extern "C" fn blazen_checkpoint_store_save(
store: *const BlazenCheckpointStore,
checkpoint: *mut BlazenWorkflowCheckpoint,
) -> *mut BlazenFuture {
if store.is_null() || checkpoint.is_null() {
if !checkpoint.is_null() {
drop(unsafe { Box::from_raw(checkpoint) });
}
return std::ptr::null_mut();
}
let store = unsafe { &*store };
let checkpoint = unsafe { Box::from_raw(checkpoint) };
let inner_checkpoint = checkpoint.0;
let store_inner = Arc::clone(&store.0);
BlazenFuture::spawn::<(), _>(async move { store_inner.save(inner_checkpoint).await })
}
#[unsafe(no_mangle)]
pub unsafe extern "C" fn blazen_checkpoint_store_load_blocking(
store: *const BlazenCheckpointStore,
run_id: *const c_char,
out_checkpoint: *mut *mut BlazenWorkflowCheckpoint,
out_found: *mut i32,
out_err: *mut *mut BlazenError,
) -> i32 {
if store.is_null() {
return -2;
}
let store = unsafe { &*store };
let Some(run_id) = (unsafe { cstr_to_str(run_id) }) else {
return -2;
};
let run_id = run_id.to_owned();
let store_inner = Arc::clone(&store.0);
let result = runtime().block_on(async move { store_inner.load(run_id).await });
match result {
Ok(Some(v)) => {
if !out_checkpoint.is_null() {
unsafe {
*out_checkpoint = BlazenWorkflowCheckpoint::from(v).into_ptr();
}
}
if !out_found.is_null() {
unsafe {
*out_found = 1;
}
}
0
}
Ok(None) => {
if !out_found.is_null() {
unsafe {
*out_found = 0;
}
}
0
}
Err(e) => {
if !out_err.is_null() {
unsafe {
*out_err = BlazenError::from(e).into_ptr();
}
}
-1
}
}
}
#[unsafe(no_mangle)]
pub unsafe extern "C" fn blazen_checkpoint_store_load(
store: *const BlazenCheckpointStore,
run_id: *const c_char,
) -> *mut BlazenFuture {
if store.is_null() {
return std::ptr::null_mut();
}
let store = unsafe { &*store };
let Some(run_id) = (unsafe { cstr_to_str(run_id) }) else {
return std::ptr::null_mut();
};
let run_id = run_id.to_owned();
let store_inner = Arc::clone(&store.0);
BlazenFuture::spawn::<Option<InnerWorkflowCheckpoint>, _>(async move {
store_inner.load(run_id).await
})
}
#[unsafe(no_mangle)]
pub unsafe extern "C" fn blazen_checkpoint_store_delete_blocking(
store: *const BlazenCheckpointStore,
run_id: *const c_char,
out_err: *mut *mut BlazenError,
) -> i32 {
if store.is_null() {
return -2;
}
let store = unsafe { &*store };
let Some(run_id) = (unsafe { cstr_to_str(run_id) }) else {
return -2;
};
let run_id = run_id.to_owned();
let store_inner = Arc::clone(&store.0);
let result = runtime().block_on(async move { store_inner.delete(run_id).await });
match result {
Ok(()) => 0,
Err(e) => {
if !out_err.is_null() {
unsafe {
*out_err = BlazenError::from(e).into_ptr();
}
}
-1
}
}
}
#[unsafe(no_mangle)]
pub unsafe extern "C" fn blazen_checkpoint_store_delete(
store: *const BlazenCheckpointStore,
run_id: *const c_char,
) -> *mut BlazenFuture {
if store.is_null() {
return std::ptr::null_mut();
}
let store = unsafe { &*store };
let Some(run_id) = (unsafe { cstr_to_str(run_id) }) else {
return std::ptr::null_mut();
};
let run_id = run_id.to_owned();
let store_inner = Arc::clone(&store.0);
BlazenFuture::spawn::<(), _>(async move { store_inner.delete(run_id).await })
}
#[unsafe(no_mangle)]
pub unsafe extern "C" fn blazen_checkpoint_store_list_blocking(
store: *const BlazenCheckpointStore,
out_array: *mut *mut *mut BlazenWorkflowCheckpoint,
out_count: *mut usize,
out_err: *mut *mut BlazenError,
) -> i32 {
if store.is_null() {
return -2;
}
let store = unsafe { &*store };
let store_inner = Arc::clone(&store.0);
let result = runtime().block_on(async move { store_inner.list().await });
match result {
Ok(items) => {
let (base, count) = checkpoints_to_c_array(items);
if out_array.is_null() {
unsafe {
let slice = std::slice::from_raw_parts_mut(base, count);
let owned = Box::from_raw(slice);
for &ptr in &owned {
if !ptr.is_null() {
drop(Box::from_raw(ptr));
}
}
drop(owned);
}
} else {
unsafe {
*out_array = base;
}
}
if !out_count.is_null() {
unsafe {
*out_count = count;
}
}
0
}
Err(e) => {
if !out_err.is_null() {
unsafe {
*out_err = BlazenError::from(e).into_ptr();
}
}
-1
}
}
}
#[unsafe(no_mangle)]
pub unsafe extern "C" fn blazen_checkpoint_store_list(
store: *const BlazenCheckpointStore,
) -> *mut BlazenFuture {
if store.is_null() {
return std::ptr::null_mut();
}
let store = unsafe { &*store };
let store_inner = Arc::clone(&store.0);
BlazenFuture::spawn::<Vec<InnerWorkflowCheckpoint>, _>(async move { store_inner.list().await })
}
#[unsafe(no_mangle)]
pub unsafe extern "C" fn blazen_checkpoint_store_list_run_ids_blocking(
store: *const BlazenCheckpointStore,
out_array: *mut *mut *mut c_char,
out_count: *mut usize,
out_err: *mut *mut BlazenError,
) -> i32 {
if store.is_null() {
return -2;
}
let store = unsafe { &*store };
let store_inner = Arc::clone(&store.0);
let result = runtime().block_on(async move { store_inner.list_run_ids().await });
match result {
Ok(items) => {
let (base, count) = strings_to_c_array(items);
if out_array.is_null() {
unsafe {
let slice = std::slice::from_raw_parts_mut(base, count);
let owned = Box::from_raw(slice);
for &ptr in &owned {
if !ptr.is_null() {
drop(std::ffi::CString::from_raw(ptr));
}
}
drop(owned);
}
} else {
unsafe {
*out_array = base;
}
}
if !out_count.is_null() {
unsafe {
*out_count = count;
}
}
0
}
Err(e) => {
if !out_err.is_null() {
unsafe {
*out_err = BlazenError::from(e).into_ptr();
}
}
-1
}
}
}
#[unsafe(no_mangle)]
pub unsafe extern "C" fn blazen_checkpoint_store_list_run_ids(
store: *const BlazenCheckpointStore,
) -> *mut BlazenFuture {
if store.is_null() {
return std::ptr::null_mut();
}
let store = unsafe { &*store };
let store_inner = Arc::clone(&store.0);
BlazenFuture::spawn::<Vec<String>, _>(async move { store_inner.list_run_ids().await })
}
#[unsafe(no_mangle)]
pub unsafe extern "C" fn blazen_checkpoint_store_free(store: *mut BlazenCheckpointStore) {
if store.is_null() {
return;
}
drop(unsafe { Box::from_raw(store) });
}
#[unsafe(no_mangle)]
pub unsafe extern "C" fn blazen_workflow_checkpoint_array_free(
arr: *mut *mut BlazenWorkflowCheckpoint,
count: usize,
) {
if arr.is_null() {
return;
}
unsafe {
let slice = std::slice::from_raw_parts_mut(arr, count);
let owned = Box::from_raw(slice);
for &ptr in &owned {
if !ptr.is_null() {
drop(Box::from_raw(ptr));
}
}
drop(owned);
}
}
#[unsafe(no_mangle)]
pub unsafe extern "C" fn blazen_string_array_free(arr: *mut *mut c_char, count: usize) {
if arr.is_null() {
return;
}
unsafe {
let slice = std::slice::from_raw_parts_mut(arr, count);
let owned = Box::from_raw(slice);
for &ptr in &owned {
if !ptr.is_null() {
drop(std::ffi::CString::from_raw(ptr));
}
}
drop(owned);
}
}
#[unsafe(no_mangle)]
pub unsafe extern "C" fn blazen_future_take_unit(
fut: *mut BlazenFuture,
err: *mut *mut BlazenError,
) -> i32 {
match unsafe { BlazenFuture::take_typed::<()>(fut) } {
Ok(()) => 0,
Err(e) => {
if !err.is_null() {
unsafe {
*err = BlazenError::from(e).into_ptr();
}
}
-1
}
}
}
#[unsafe(no_mangle)]
pub unsafe extern "C" fn blazen_future_take_workflow_checkpoint_option(
fut: *mut BlazenFuture,
out: *mut *mut BlazenWorkflowCheckpoint,
out_found: *mut i32,
err: *mut *mut BlazenError,
) -> i32 {
match unsafe { BlazenFuture::take_typed::<Option<InnerWorkflowCheckpoint>>(fut) } {
Ok(Some(v)) => {
if !out.is_null() {
unsafe {
*out = BlazenWorkflowCheckpoint::from(v).into_ptr();
}
}
if !out_found.is_null() {
unsafe {
*out_found = 1;
}
}
0
}
Ok(None) => {
if !out_found.is_null() {
unsafe {
*out_found = 0;
}
}
0
}
Err(e) => {
if !err.is_null() {
unsafe {
*err = BlazenError::from(e).into_ptr();
}
}
-1
}
}
}
#[unsafe(no_mangle)]
pub unsafe extern "C" fn blazen_future_take_workflow_checkpoint_list(
fut: *mut BlazenFuture,
out_array: *mut *mut *mut BlazenWorkflowCheckpoint,
out_count: *mut usize,
err: *mut *mut BlazenError,
) -> i32 {
match unsafe { BlazenFuture::take_typed::<Vec<InnerWorkflowCheckpoint>>(fut) } {
Ok(items) => {
let (base, count) = checkpoints_to_c_array(items);
if out_array.is_null() {
unsafe {
let slice = std::slice::from_raw_parts_mut(base, count);
let owned = Box::from_raw(slice);
for &ptr in &owned {
if !ptr.is_null() {
drop(Box::from_raw(ptr));
}
}
drop(owned);
}
} else {
unsafe {
*out_array = base;
}
}
if !out_count.is_null() {
unsafe {
*out_count = count;
}
}
0
}
Err(e) => {
if !err.is_null() {
unsafe {
*err = BlazenError::from(e).into_ptr();
}
}
-1
}
}
}
#[unsafe(no_mangle)]
pub unsafe extern "C" fn blazen_future_take_string_list(
fut: *mut BlazenFuture,
out_array: *mut *mut *mut c_char,
out_count: *mut usize,
err: *mut *mut BlazenError,
) -> i32 {
match unsafe { BlazenFuture::take_typed::<Vec<String>>(fut) } {
Ok(items) => {
let (base, count) = strings_to_c_array(items);
if out_array.is_null() {
unsafe {
let slice = std::slice::from_raw_parts_mut(base, count);
let owned = Box::from_raw(slice);
for &ptr in &owned {
if !ptr.is_null() {
drop(std::ffi::CString::from_raw(ptr));
}
}
drop(owned);
}
} else {
unsafe {
*out_array = base;
}
}
if !out_count.is_null() {
unsafe {
*out_count = count;
}
}
0
}
Err(e) => {
if !err.is_null() {
unsafe {
*err = BlazenError::from(e).into_ptr();
}
}
-1
}
}
}