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