#![allow(unsafe_code)]
use std::os::raw::c_void;
use std::panic::catch_unwind;
use super::types::RssnStatus;
use crate::dag::builder::DagBuilder;
use crate::dag::node::DagNodeId;
use crate::heuristic::{HeuristicConfig, HeuristicEngine, SearchStrategy};
use crate::runtime::{TaskHandle, ensure_runtime, join, spawn_task};
#[repr(C)]
pub struct RssnAsyncHandle {
pub handle_id: u64,
pub simplified_root: u32,
pub status: RssnStatus,
}
#[unsafe(no_mangle)]
#[allow(clippy::not_unsafe_ptr_arg_deref)]
pub extern "C" fn rssn_dag_simplify_async(
builder: *mut DagBuilder,
root: u32,
) -> *mut RssnAsyncHandle {
let handle_box = Box::new(RssnAsyncHandle {
handle_id: u64::MAX,
simplified_root: u32::MAX,
status: RssnStatus::NullPointer,
});
let handle_ptr = Box::into_raw(handle_box);
if builder.is_null() {
return handle_ptr;
}
let builder_addr = builder as usize;
let handle_addr = handle_ptr as usize;
let gate = ensure_runtime();
let task = spawn_task(gate, move || {
let result = catch_unwind(std::panic::AssertUnwindSafe(|| {
let builder_ref = unsafe { &mut *(builder_addr as *mut DagBuilder) };
let root_id = DagNodeId::new(root);
let config = HeuristicConfig::default();
let mut engine = HeuristicEngine::new(config, SearchStrategy::Greedy);
engine.simplify(builder_ref, root_id).value()
}));
let h = unsafe { &mut *(handle_addr as *mut RssnAsyncHandle) };
match result {
Ok(simplified) => {
h.simplified_root = simplified;
h.status = RssnStatus::Success;
}
Err(_) => {
h.status = RssnStatus::Panic;
}
}
});
unsafe {
(*handle_ptr).handle_id = task.raw_id();
}
handle_ptr
}
#[unsafe(no_mangle)]
#[allow(clippy::not_unsafe_ptr_arg_deref)]
pub extern "C" fn rssn_async_join(handle: *mut RssnAsyncHandle, out_root: *mut u32) -> RssnStatus {
if handle.is_null() {
return RssnStatus::NullPointer;
}
let h = unsafe { &*handle };
if h.handle_id != u64::MAX {
let task_handle = TaskHandle::from_raw(h.handle_id);
join(task_handle);
}
let h = unsafe { &*handle };
if !out_root.is_null() {
unsafe { *out_root = h.simplified_root };
}
let status = h.status;
let _ = unsafe { Box::from_raw(handle) };
status
}
#[repr(C)]
pub struct RssnAsyncCompileHandle {
pub handle_id: u64,
pub fn_ptr_bits: u64,
pub status: RssnStatus,
}
unsafe impl Send for RssnAsyncCompileHandle {}
#[cfg(feature = "cranelift-jit")]
#[unsafe(no_mangle)]
#[allow(clippy::not_unsafe_ptr_arg_deref)]
pub extern "C" fn rssn_dag_compile_async(
builder: *mut DagBuilder,
root: u32,
) -> *mut RssnAsyncCompileHandle {
let handle_box = Box::new(RssnAsyncCompileHandle {
handle_id: u64::MAX,
fn_ptr_bits: 0,
status: RssnStatus::NullPointer,
});
let handle_ptr = Box::into_raw(handle_box);
if builder.is_null() {
return handle_ptr;
}
let builder_addr = builder as usize;
let handle_addr = handle_ptr as usize;
let gate = ensure_runtime();
let task = spawn_task(gate, move || {
let result = catch_unwind(std::panic::AssertUnwindSafe(|| {
let builder_ref = unsafe { &mut *(builder_addr as *mut DagBuilder) };
let root_id = DagNodeId::new(root);
let config = HeuristicConfig::default();
let mut engine = HeuristicEngine::new(config, SearchStrategy::Greedy);
let simplified_id = engine.simplify(builder_ref, root_id);
let ast = crate::ast::convert::dag_to_ast(builder_ref.arena(), simplified_id);
let ctx_mutex = crate::ffi::jit_context::global_jit_ctx();
let mut ctx = ctx_mutex
.lock()
.unwrap_or_else(std::sync::PoisonError::into_inner);
ctx.compiler_mut().compile(&ast).map(|f| f as usize as u64)
}));
let h = unsafe { &mut *(handle_addr as *mut RssnAsyncCompileHandle) };
match result {
Ok(Ok(fn_bits)) => {
h.fn_ptr_bits = fn_bits;
h.status = RssnStatus::Success;
}
Ok(Err(_)) => {
h.status = RssnStatus::CompilationError;
}
Err(_) => {
h.status = RssnStatus::Panic;
}
}
});
unsafe { (*handle_ptr).handle_id = task.raw_id() };
handle_ptr
}
#[cfg(not(feature = "cranelift-jit"))]
#[unsafe(no_mangle)]
#[allow(clippy::not_unsafe_ptr_arg_deref)]
pub extern "C" fn rssn_dag_compile_async(
_builder: *mut DagBuilder,
_root: u32,
) -> *mut RssnAsyncCompileHandle {
Box::into_raw(Box::new(RssnAsyncCompileHandle {
handle_id: u64::MAX,
fn_ptr_bits: 0,
status: RssnStatus::CompilationError,
}))
}
#[unsafe(no_mangle)]
#[allow(clippy::not_unsafe_ptr_arg_deref)]
pub extern "C" fn rssn_async_compile_join(
handle: *mut RssnAsyncCompileHandle,
out_fn: *mut *mut c_void,
) -> RssnStatus {
if handle.is_null() {
return RssnStatus::NullPointer;
}
let h = unsafe { &*handle };
if h.handle_id != u64::MAX {
let task_handle = TaskHandle::from_raw(h.handle_id);
join(task_handle);
}
let h = unsafe { &*handle };
if !out_fn.is_null() {
unsafe { *out_fn = h.fn_ptr_bits as *mut c_void };
}
let status = h.status;
let _ = unsafe { Box::from_raw(handle) };
status
}
#[repr(C)]
pub struct RssnAsyncEvalHandle {
pub handle_id: u64,
pub result: f64,
pub status: RssnStatus,
}
unsafe impl Send for RssnAsyncEvalHandle {}
#[cfg(feature = "cranelift-jit")]
#[unsafe(no_mangle)]
#[allow(clippy::not_unsafe_ptr_arg_deref)]
pub extern "C" fn rssn_dag_eval_async(
builder: *mut DagBuilder,
root: u32,
vars: *const f64,
) -> *mut RssnAsyncEvalHandle {
let handle_box = Box::new(RssnAsyncEvalHandle {
handle_id: u64::MAX,
result: f64::NAN,
status: RssnStatus::NullPointer,
});
let handle_ptr = Box::into_raw(handle_box);
if builder.is_null() || vars.is_null() {
return handle_ptr;
}
let builder_addr = builder as usize;
let vars_addr = vars as usize;
let handle_addr = handle_ptr as usize;
let gate = ensure_runtime();
let task = spawn_task(gate, move || {
let result = catch_unwind(std::panic::AssertUnwindSafe(|| {
let builder_ref = unsafe { &mut *(builder_addr as *mut DagBuilder) };
let vars_ptr = vars_addr as *const f64;
let root_id = DagNodeId::new(root);
let config = HeuristicConfig::default();
let mut engine = HeuristicEngine::new(config, SearchStrategy::Greedy);
let simplified_id = engine.simplify(builder_ref, root_id);
let ast = crate::ast::convert::dag_to_ast(builder_ref.arena(), simplified_id);
let compiled_fn = {
let ctx_mutex = crate::ffi::jit_context::global_jit_ctx();
let mut ctx = ctx_mutex
.lock()
.unwrap_or_else(std::sync::PoisonError::into_inner);
ctx.compiler_mut().compile(&ast)?
};
Ok::<f64, crate::error::JitError>(compiled_fn(vars_ptr))
}));
let h = unsafe { &mut *(handle_addr as *mut RssnAsyncEvalHandle) };
match result {
Ok(Ok(val)) => {
h.result = val;
h.status = RssnStatus::Success;
}
Ok(Err(_)) => {
h.status = RssnStatus::CompilationError;
}
Err(_) => {
h.status = RssnStatus::Panic;
}
}
});
unsafe { (*handle_ptr).handle_id = task.raw_id() };
handle_ptr
}
#[cfg(not(feature = "cranelift-jit"))]
#[unsafe(no_mangle)]
#[allow(clippy::not_unsafe_ptr_arg_deref)]
pub extern "C" fn rssn_dag_eval_async(
_builder: *mut DagBuilder,
_root: u32,
_vars: *const f64,
) -> *mut RssnAsyncEvalHandle {
Box::into_raw(Box::new(RssnAsyncEvalHandle {
handle_id: u64::MAX,
result: f64::NAN,
status: RssnStatus::CompilationError,
}))
}
#[unsafe(no_mangle)]
#[allow(clippy::not_unsafe_ptr_arg_deref)]
pub extern "C" fn rssn_async_eval_join(
handle: *mut RssnAsyncEvalHandle,
out_val: *mut f64,
) -> RssnStatus {
if handle.is_null() {
return RssnStatus::NullPointer;
}
let h = unsafe { &*handle };
if h.handle_id != u64::MAX {
let task_handle = TaskHandle::from_raw(h.handle_id);
join(task_handle);
}
let h = unsafe { &*handle };
if !out_val.is_null() {
unsafe { *out_val = h.result };
}
let status = h.status;
let _ = unsafe { Box::from_raw(handle) };
status
}