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