use std::os::raw::c_int;
use std::panic::AssertUnwindSafe;
use wolfram_expr::Expr;
use wolfram_library_link::macro_utils::call_and_catch_as_expr;
use wolfram_library_link::sys::{self, MArgument};
use wolfram_library_link::{NativeFunction, NumericArray};
use wolfram_serialize::{from_wxf, to_wxf, ExpressionEnum, SliceReader, WxfReader};
pub use wolfram_serialize::{FromWXF, ToWXF};
pub fn wxf_signature() -> Result<(Vec<Expr>, Expr), String> {
Ok((vec![Expr::string("ByteArray")], Expr::string("ByteArray")))
}
pub fn decode<A: for<'de> FromWXF<'de>>(input: &NumericArray<u8>) -> Result<A, String> {
from_wxf::<A>(input.as_slice()).map_err(|e| format!("{e:?}"))
}
pub fn decode_args<R, F>(
input: &NumericArray<u8>,
n_expected: u64,
read: F,
) -> Result<R, wolfram_serialize::Error>
where
F: for<'a> FnOnce(&mut WxfReader<SliceReader<'a>>) -> Result<R, wolfram_serialize::Error>,
{
wolfram_serialize::read_wxf(input.as_slice(), |r| {
let tok = r.read_expr_token()?;
if tok != ExpressionEnum::Function {
return Err(wolfram_serialize::Error::unexpected_token(&["Function"], tok));
}
let n = r.read_varint()?;
r.skip()?; if n != n_expected {
return Err(wolfram_serialize::Error::ArgCountMismatch {
expected: n_expected,
got: n,
});
}
read(r)
})
}
pub fn encode<R: ToWXF>(value: &R) -> NumericArray<u8> {
let bytes: Vec<u8> =
to_wxf(value, None).unwrap_or_else(|e| panic!("WXF serialize failed: {:?}", e));
NumericArray::<u8>::from_slice(&bytes)
}
pub fn encode_arg_error(e: wolfram_serialize::Error) -> NumericArray<u8> {
encode(&wolfram_expr::expr!(
System::Failure["ArgumentError", { "Message" -> (format!("{e:?}")) }]
))
}
pub fn to_wxf_bytes<R: ToWXF>(value: &R) -> Result<Vec<u8>, wolfram_serialize::Error> {
to_wxf(value, None)
}
pub fn call_and_encode_panic<F>(func: F) -> NumericArray<u8>
where
F: FnOnce() -> NumericArray<u8>,
{
match call_and_catch_as_expr(AssertUnwindSafe(func)) {
Ok(result) => result,
Err(failure_expr) => encode(&failure_expr),
}
}
pub trait WxfFunction {}
impl<A: for<'de> FromWXF<'de>, R: ToWXF> WxfFunction for fn(A) -> R {}
pub unsafe fn call_wxf_wolfram_library_function<'a, F: NativeFunction<'a>>(
lib_data: sys::WolframLibraryData,
args: *mut MArgument,
argc: sys::mint,
res: MArgument,
func: F,
) -> c_int {
if wolfram_library_link::initialize(lib_data).is_err() {
return wolfram_library_link::FAILED_TO_INIT;
}
let argc = match usize::try_from(argc) {
Ok(argc) => argc,
Err(_) => return wolfram_library_link::sys::LIBRARY_FUNCTION_ERROR as c_int,
};
let args: &[MArgument] = std::slice::from_raw_parts(args, argc);
if call_and_catch_as_expr(AssertUnwindSafe(move || func.call(args, res))).is_err() {
return wolfram_library_link::FAILED_WITH_PANIC;
}
sys::LIBRARY_NO_ERROR as c_int
}