1use std::{2 borrow::Cow,3 ffi::{c_void, CStr},4 os::raw::{c_char, c_int},5};67use jrsonnet_evaluator::{8 error::{Error, ErrorKind},9 function::builtin::{NativeCallback, NativeCallbackHandler},10 tb,11 typed::Typed,12 IStr, Val,13};14use jrsonnet_gcmodule::Cc;1516use crate::VM;1718192021222324252627type JsonnetNativeCallback = unsafe extern "C" fn(28 ctx: *const c_void,29 argv: *const *const Val,30 success: *mut c_int,31) -> *mut Val;3233#[derive(jrsonnet_gcmodule::Trace)]34struct JsonnetNativeCallbackHandler {35 #[trace(skip)]36 ctx: *const c_void,37 #[trace(skip)]38 cb: JsonnetNativeCallback,39}40impl NativeCallbackHandler for JsonnetNativeCallbackHandler {41 fn call(&self, args: &[Val]) -> Result<Val, Error> {42 let mut n_args = Vec::new();43 for a in args {44 n_args.push(Some(Box::new(a.clone())));45 }46 n_args.push(None);47 let mut success = 1;48 let v = unsafe {49 (self.cb)(50 self.ctx,51 &n_args as *const _ as *const *const Val,52 &mut success,53 )54 };55 let v = unsafe { *Box::from_raw(v) };56 if success == 1 {57 Ok(v)58 } else {59 let e = IStr::from_untyped(v).expect("error msg should be a string");60 Err(ErrorKind::RuntimeError(e).into())61 }62 }63}64656667686970717273#[no_mangle]74pub unsafe extern "C" fn jsonnet_native_callback(75 vm: &VM,76 name: *const c_char,77 cb: JsonnetNativeCallback,78 ctx: *const c_void,79 mut raw_params: *const *const c_char,80) {81 let name = CStr::from_ptr(name)82 .to_str()83 .expect("name is not utf-8")84 .into();85 let mut params = Vec::new();86 loop {87 if (*raw_params).is_null() {88 break;89 }90 let param = CStr::from_ptr(*raw_params)91 .to_str()92 .expect("param name is not utf-8");93 params.push(Cow::Owned(param.into()));94 raw_params = raw_params.offset(1);95 }9697 let any_resolver = vm.state.context_initializer();98 any_resolver99 .as_any()100 .downcast_ref::<jrsonnet_stdlib::ContextInitializer>()101 .expect("only stdlib context initializer supported")102 .add_native(103 name,104 #[allow(deprecated)]105 Cc::new(tb!(NativeCallback::new(106 params,107 tb!(JsonnetNativeCallbackHandler { ctx, cb }),108 ))),109 )110}