git.delta.rocks / jrsonnet / refs/commits / 07648052cee3

difftreelog

source

bindings/jsonnet/src/native.rs2.8 KiBsourcehistory
1use std::{2	ffi::{c_void, CStr},3	os::raw::{c_char, c_int},4};56use jrsonnet_evaluator::{7	error::{Error, ErrorKind},8	function::builtin::{NativeCallback, NativeCallbackHandler},9	typed::Typed,10	IStr, Val,11};1213use crate::VM;1415/// The returned `JsonnetJsonValue*` should be allocated with `jsonnet_realloc`. It will be cleaned up16/// along with the objects rooted at `argv` by `libjsonnet` when no-longer needed. Return a string upon17/// failure, which will appear in Jsonnet as an error. The `argv` pointer is an array whose size18/// matches the array of parameters supplied when the native callback was originally registered.19///20/// - `ctx` User pointer, given in jsonnet_native_callback.21/// - `argv` Array of arguments from Jsonnet code.22/// - `param` success Set this byref param to 1 to indicate success and 0 for failure.23/// Returns the content of the imported file, or an error message.24type JsonnetNativeCallback = unsafe extern "C" fn(25	ctx: *const c_void,26	argv: *const *const Val,27	success: *mut c_int,28) -> *mut Val;2930#[derive(jrsonnet_gcmodule::Trace)]31struct JsonnetNativeCallbackHandler {32	#[trace(skip)]33	ctx: *const c_void,34	#[trace(skip)]35	cb: JsonnetNativeCallback,36}37impl NativeCallbackHandler for JsonnetNativeCallbackHandler {38	fn call(&self, args: &[Val]) -> Result<Val, Error> {39		let mut n_args = Vec::new();40		for a in args {41			n_args.push(Some(Box::new(a.clone())));42		}43		n_args.push(None);44		let mut success = 1;45		let v = unsafe { (self.cb)(self.ctx, n_args.as_ptr().cast(), &mut success) };46		let v = unsafe { *Box::from_raw(v) };47		if success == 1 {48			Ok(v)49		} else {50			let e = IStr::from_untyped(v).expect("error msg should be a string");51			Err(ErrorKind::RuntimeError(e).into())52		}53	}54}5556/// Callback to provide native extensions to Jsonnet.57///58/// # Safety59///60/// `vm` should be a vm allocated by `jsonnet_make`61/// `name` should be a NUL-terminated string62/// `cb` should be a function pointer63/// `raw_params` should point to a NULL-terminated array of NUL-terminated strings64#[no_mangle]65pub unsafe extern "C" fn jsonnet_native_callback(66	vm: &VM,67	name: *const c_char,68	cb: JsonnetNativeCallback,69	ctx: *const c_void,70	mut raw_params: *const *const c_char,71) {72	let name = CStr::from_ptr(name).to_str().expect("name is not utf-8");73	let mut params = Vec::new();74	loop {75		if (*raw_params).is_null() {76			break;77		}78		let param = CStr::from_ptr(*raw_params)79			.to_str()80			.expect("param name is not utf-8");81		params.push(param.into());82		raw_params = raw_params.offset(1);83	}8485	let any_resolver = vm.state.context_initializer();86	any_resolver87		.as_any()88		.downcast_ref::<jrsonnet_stdlib::ContextInitializer>()89		.expect("only stdlib context initializer supported")90		.add_native(91			name,92			#[allow(deprecated)]93			NativeCallback::new(params, JsonnetNativeCallbackHandler { ctx, cb }),94		)95}