git.delta.rocks / jrsonnet / refs/commits / ff649630ca7e

difftreelog

source

bindings/jsonnet/src/native.rs2.9 KiBsourcehistory
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;1718/// The returned `JsonnetJsonValue*` should be allocated with `jsonnet_realloc`. It will be cleaned up19/// along with the objects rooted at `argv` by `libjsonnet` when no-longer needed. Return a string upon20/// failure, which will appear in Jsonnet as an error. The `argv` pointer is an array whose size21/// matches the array of parameters supplied when the native callback was originally registered.22///23/// - `ctx` User pointer, given in jsonnet_native_callback.24/// - `argv` Array of arguments from Jsonnet code.25/// - `param` success Set this byref param to 1 to indicate success and 0 for failure.26/// Returns the content of the imported file, or an error message.27type 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}6465/// Callback to provide native extensions to Jsonnet.66///67/// # Safety68///69/// `vm` should be a vm allocated by `jsonnet_make`70/// `name` should be a NUL-terminated string71/// `cb` should be a function pointer72/// `raw_params` should point to a NULL-terminated array of NUL-terminated strings73#[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}