mirtal-sys 0.3.0

Private native bridge for mirtal
use crate::ffi;

type CallbackResult = std::result::Result<Vec<cxx::SharedPtr<ffi::Array>>, String>;
type Callback = dyn Fn(Vec<cxx::SharedPtr<ffi::Array>>, &ffi::Stream) -> CallbackResult + Send;

pub struct GraphCallback {
    function: Box<Callback>,
}

pub fn graph_callback(
    function: impl Fn(Vec<cxx::SharedPtr<ffi::Array>>, &ffi::Stream) -> CallbackResult + Send + 'static,
) -> Box<GraphCallback> {
    Box::new(GraphCallback { function: Box::new(function) })
}

pub fn invoke_graph(
    callback: &GraphCallback,
    inputs: cxx::UniquePtr<ffi::Arrays>,
) -> std::result::Result<cxx::UniquePtr<ffi::Arrays>, String> {
    let result = std::panic::catch_unwind(std::panic::AssertUnwindSafe(|| {
        let stream = native_stream(&inputs)?;
        let values = native_arrays(&inputs)?;
        (callback.function)(values, stream)
    }));
    drop(inputs);
    let values = match result {
        Ok(values) => values?,
        Err(_) => return Err("compiled Rust graph callback panicked".into()),
    };
    let mut outputs = ffi::new_arrays();
    for value in values {
        let value = value.as_ref().ok_or_else(|| "graph returned a null array".to_owned())?;
        ffi::arrays_push(outputs.pin_mut(), value);
    }
    Ok(outputs)
}

fn native_arrays(
    arrays: &cxx::UniquePtr<ffi::Arrays>,
) -> std::result::Result<Vec<cxx::SharedPtr<ffi::Array>>, String> {
    let arrays = arrays.as_ref().ok_or_else(|| "compiled graph inputs are null".to_owned())?;
    (0..ffi::arrays_len(arrays))
        .map(|index| string_result(ffi::arrays_get(arrays, index)))
        .collect()
}

fn native_stream(
    arrays: &cxx::UniquePtr<ffi::Arrays>,
) -> std::result::Result<&ffi::Stream, String> {
    let arrays = arrays.as_ref().ok_or_else(|| "compiled graph inputs are null".to_owned())?;
    string_result(ffi::arrays_stream(arrays))
}

fn string_result<T, E: std::fmt::Display>(
    result: std::result::Result<T, E>,
) -> std::result::Result<T, String> {
    match result {
        Ok(value) => Ok(value),
        Err(error) => Err(error.to_string()),
    }
}