git.delta.rocks / jrsonnet / refs/commits / 097494ede5f1

difftreelog

source

bindings/jsonnet/src/native.rs3.0 KiBsourcehistory
1use std::{2	ffi::{c_void, CStr},3	os::raw::{c_char, c_int},4};56use jrsonnet_evaluator::{7	error::{Error, LocError},8	function::builtin::{BuiltinParam, NativeCallback, NativeCallbackHandler},9	tb,10	typed::Typed,11	IStr, State, Val,12};13use jrsonnet_gcmodule::Cc;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, s: State, args: &[Val]) -> Result<Val, LocError> {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 {46			(self.cb)(47				self.ctx,48				&n_args as *const _ as *const *const Val,49				&mut success,50			)51		};52		let v = unsafe { *Box::from_raw(v) };53		if success == 1 {54			Ok(v)55		} else {56			let e = IStr::from_untyped(v, s).expect("error msg should be a string");57			Err(Error::RuntimeError(e).into())58		}59	}60}6162/// Callback to provide native extensions to Jsonnet.63///64/// # Safety65///66/// `vm` should be a vm allocated by `jsonnet_make`67/// `cb` should be a correct function pointer68/// `raw_params` should point to a NULL-terminated string array69/// `name`, `raw_params` elements should be a \0-terminated strings70#[no_mangle]71pub unsafe extern "C" fn jsonnet_native_callback(72	vm: &State,73	name: *const c_char,74	cb: JsonnetNativeCallback,75	ctx: *const c_void,76	mut raw_params: *const *const c_char,77) {78	let name = CStr::from_ptr(name)79		.to_str()80		.expect("name is not utf-8")81		.into();82	let mut params = Vec::new();83	loop {84		if (*raw_params).is_null() {85			break;86		}87		let param = CStr::from_ptr(*raw_params)88			.to_str()89			.expect("param name is not utf-8");90		params.push(BuiltinParam {91			name: param.into(),92			has_default: false,93		});94		raw_params = raw_params.offset(1);95	}9697	let any_resolver = vm.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}