1use std::{2 ffi::{c_void, CStr},3 os::raw::{c_char, c_int},4};56use jrsonnet_evaluator::{7 error::{Error, LocError},8 function::builtin::{BuiltinParam, NativeCallback, NativeCallbackHandler},9 tb,10 typed::Typed,11 IStr, State, Val,12};13use jrsonnet_gcmodule::Cc;1415type JsonnetNativeCallback = unsafe extern "C" fn(16 ctx: *const c_void,17 argv: *const *const Val,18 success: *mut c_int,19) -> *mut Val;2021#[derive(jrsonnet_gcmodule::Trace)]22struct JsonnetNativeCallbackHandler {23 #[trace(skip)]24 ctx: *const c_void,25 #[trace(skip)]26 cb: JsonnetNativeCallback,27}28impl NativeCallbackHandler for JsonnetNativeCallbackHandler {29 fn call(&self, s: State, args: &[Val]) -> Result<Val, LocError> {30 let mut n_args = Vec::new();31 for a in args {32 n_args.push(Some(Box::new(a.clone())));33 }34 n_args.push(None);35 let mut success = 1;36 let v = unsafe {37 (self.cb)(38 self.ctx,39 &n_args as *const _ as *const *const Val,40 &mut success,41 )42 };43 let v = unsafe { *Box::from_raw(v) };44 if success == 1 {45 Ok(v)46 } else {47 let e = IStr::from_untyped(v, s).expect("error msg");48 Err(Error::RuntimeError(e).into())49 }50 }51}525354#[no_mangle]55pub unsafe extern "C" fn jsonnet_native_callback(56 vm: &State,57 name: *const c_char,58 cb: JsonnetNativeCallback,59 ctx: *const c_void,60 mut raw_params: *const *const c_char,61) {62 let name = CStr::from_ptr(name).to_str().expect("utf8 name").into();63 let mut params = Vec::new();64 loop {65 if (*raw_params).is_null() {66 break;67 }68 let param = CStr::from_ptr(*raw_params).to_str().expect("not utf8");69 params.push(BuiltinParam {70 name: param.into(),71 has_default: false,72 });73 raw_params = raw_params.offset(1);74 }7576 vm.add_native(77 name,78 #[allow(deprecated)]79 Cc::new(tb!(NativeCallback::new(80 params,81 tb!(JsonnetNativeCallbackHandler { ctx, cb }),82 ))),83 )84}