1use std::{2 convert::TryFrom,3 ffi::{c_void, CStr},4 os::raw::{c_char, c_int},5 path::Path,6 rc::Rc,7};89use gcmodule::Cc;10use jrsonnet_evaluator::{11 error::{Error, LocError},12 function::BuiltinParam,13 gc::TraceBox,14 native::{NativeCallback, NativeCallbackHandler},15 EvaluationState, IStr, Val,16};1718type JsonnetNativeCallback = unsafe extern "C" fn(19 ctx: *const c_void,20 argv: *const *const Val,21 success: *mut c_int,22) -> *mut Val;2324#[derive(gcmodule::Trace)]25struct JsonnetNativeCallbackHandler {26 #[skip_trace]27 ctx: *const c_void,28 #[skip_trace]29 cb: JsonnetNativeCallback,30}31impl NativeCallbackHandler for JsonnetNativeCallbackHandler {32 fn call(&self, _from: Option<Rc<Path>>, args: &[Val]) -> Result<Val, LocError> {33 let mut n_args = Vec::new();34 for a in args {35 n_args.push(Some(Box::new(a.clone())));36 }37 n_args.push(None);38 let mut success = 1;39 let v = unsafe {40 (self.cb)(41 self.ctx,42 &n_args as *const _ as *const *const Val,43 &mut success,44 )45 };46 let v = unsafe { *Box::from_raw(v) };47 if success == 1 {48 Ok(v)49 } else {50 let e = IStr::try_from(v).expect("error msg");51 Err(Error::RuntimeError(e).into())52 }53 }54}555657#[no_mangle]58pub unsafe extern "C" fn jsonnet_native_callback(59 vm: &EvaluationState,60 name: *const c_char,61 cb: JsonnetNativeCallback,62 ctx: *const c_void,63 mut raw_params: *const *const c_char,64) {65 let name = CStr::from_ptr(name).to_str().expect("utf8 name").into();66 let mut params = Vec::new();67 loop {68 if (*raw_params).is_null() {69 break;70 }71 let param = CStr::from_ptr(*raw_params).to_str().expect("not utf8");72 params.push(BuiltinParam {73 name: param.into(),74 has_default: false,75 });76 raw_params = raw_params.offset(1);77 }7879 vm.add_native(80 name,81 #[allow(deprecated)]82 Cc::new(TraceBox(Box::new(NativeCallback::new(83 params,84 TraceBox(Box::new(JsonnetNativeCallbackHandler { ctx, cb })),85 )))),86 )87}