1use std::{2 ffi::{c_void, CStr},3 os::raw::{c_char, c_int},4};56use jrsonnet_evaluator::{7 error::{Error, ErrorKind},8 function::builtin::{NativeCallback, NativeCallbackHandler},9 typed::Typed,10 IStr, Val,11};1213use crate::VM;1415161718192021222324type JsonnetNativeCallback = unsafe extern "C" fn(25 ctx: *const c_void,26 argv: *const *const Val,27 success: *mut c_int,28) -> *mut Val;2930#[derive(jrsonnet_gcmodule::Trace)]31struct JsonnetNativeCallbackHandler {32 #[trace(skip)]33 ctx: *const c_void,34 #[trace(skip)]35 cb: JsonnetNativeCallback,36}37impl NativeCallbackHandler for JsonnetNativeCallbackHandler {38 fn call(&self, args: &[Val]) -> Result<Val, Error> {39 let mut n_args = Vec::new();40 for a in args {41 n_args.push(Some(Box::new(a.clone())));42 }43 n_args.push(None);44 let mut success = 1;45 let v = unsafe { (self.cb)(self.ctx, n_args.as_ptr().cast(), &mut success) };46 let v = unsafe { *Box::from_raw(v) };47 if success == 1 {48 Ok(v)49 } else {50 let e = IStr::from_untyped(v).expect("error msg should be a string");51 Err(ErrorKind::RuntimeError(e).into())52 }53 }54}55565758596061626364#[no_mangle]65pub unsafe extern "C" fn jsonnet_native_callback(66 vm: &VM,67 name: *const c_char,68 cb: JsonnetNativeCallback,69 ctx: *const c_void,70 mut raw_params: *const *const c_char,71) {72 let name = unsafe { CStr::from_ptr(name).to_str().expect("name is not utf-8") };73 let mut params = Vec::new();74 loop {75 if (unsafe { *raw_params }).is_null() {76 break;77 }78 let param = unsafe {79 CStr::from_ptr(*raw_params)80 .to_str()81 .expect("param name is not utf-8")82 };83 params.push(param.into());84 raw_params = unsafe { raw_params.offset(1) };85 }8687 let any_resolver = vm.state.context_initializer();88 any_resolver89 .as_any()90 .downcast_ref::<jrsonnet_stdlib::ContextInitializer>()91 .expect("only stdlib context initializer supported")92 .add_native(93 name,94 #[allow(deprecated)]95 NativeCallback::new(params, JsonnetNativeCallbackHandler { ctx, cb }),96 );97}