git.delta.rocks / jrsonnet / refs/heads / master

difftreelog

source

bindings/jsonnet/src/native.rs2.9 KiBsourcehistory
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;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///24/// Returns the content of the imported file, or an error message.25type 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}5657/// Callback to provide native extensions to Jsonnet.58///59/// # Safety60///61/// `vm` should be a vm allocated by `jsonnet_make`62/// `name` should be a NUL-terminated string63/// `cb` should be a function pointer64/// `raw_params` should point to a NULL-terminated array of NUL-terminated strings65#[unsafe(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.add(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}