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

difftreelog

source

bindings/jsonnet/src/import.rs3.2 KiBsourcehistory
1//! Import resolution manipulation utilities23use std::{4	any::Any,5	cell::RefCell,6	collections::HashMap,7	env::current_dir,8	ffi::{c_void, CStr, CString},9	os::raw::{c_char, c_int},10	path::PathBuf,11	ptr::null_mut,12};1314use jrsonnet_evaluator::{15	error::{Error::*, Result},16	throw, FileImportResolver, ImportResolver, State,17};18use jrsonnet_parser::{SourceDirectory, SourceFile, SourcePath};1920pub type JsonnetImportCallback = unsafe extern "C" fn(21	ctx: *mut c_void,22	base: *const c_char,23	rel: *const c_char,24	found_here: *mut *const c_char,25	success: &mut c_int,26) -> *mut c_char;2728/// Resolves imports using callback29pub struct CallbackImportResolver {30	cb: JsonnetImportCallback,31	ctx: *mut c_void,32	out: RefCell<HashMap<SourcePath, Vec<u8>>>,33}34impl ImportResolver for CallbackImportResolver {35	fn resolve_from(&self, from: &SourcePath, path: &str) -> Result<SourcePath> {36		let base = if let Some(p) = from.downcast_ref::<SourceFile>() {37			let mut o = p.path().to_owned();38			o.pop();39			o40		} else if let Some(d) = from.downcast_ref::<SourceDirectory>() {41			d.path().to_owned()42		} else if from.is_default() {43			current_dir().map_err(|e| ImportIo(e.to_string()))?44		} else {45			unreachable!("can't resolve this path");46		};47		let base = unsafe { crate::unparse_path(&base) };48		let rel = CString::new(path).unwrap();49		let found_here: *mut c_char = null_mut();50		let mut success: i32 = 0;51		let result_ptr = unsafe {52			(self.cb)(53				self.ctx,54				base.as_ptr(),55				rel.as_ptr(),56				&mut (found_here as *const _),57				&mut success,58			)59		};60		let result_raw = unsafe { CStr::from_ptr(result_ptr) };61		let result_str = result_raw.to_str().unwrap();62		assert!(success == 0 || success == 1);63		if success == 0 {64			unsafe { CString::from_raw(result_ptr) };65			let result = result_str.to_owned();66			throw!(ImportCallbackError(result));67		}6869		let found_here_raw = unsafe { CStr::from_ptr(found_here) };70		let found_here_buf = SourcePath::new(SourceFile::new(PathBuf::from(71			found_here_raw.to_str().unwrap(),72		)));73		unsafe {74			let _ = CString::from_raw(found_here);75		}7677		let mut out = self.out.borrow_mut();78		if !out.contains_key(&found_here_buf) {79			out.insert(found_here_buf.clone(), result_str.into());80			unsafe { CString::from_raw(result_ptr) };81		}8283		Ok(found_here_buf)84	}85	fn load_file_contents(&self, resolved: &SourcePath) -> Result<Vec<u8>> {86		Ok(self.out.borrow().get(resolved).unwrap().clone())87	}8889	fn as_any(&self) -> &dyn Any {90		self91	}92}9394/// # Safety95///96/// Caller should pass correct callback function97#[no_mangle]98pub unsafe extern "C" fn jsonnet_import_callback(99	vm: &State,100	cb: JsonnetImportCallback,101	ctx: *mut c_void,102) {103	vm.set_import_resolver(Box::new(CallbackImportResolver {104		cb,105		ctx,106		out: RefCell::new(HashMap::new()),107	}))108}109110/// # Safety111///112/// Caller should pass correct path: it should contain correct utf-8, and be \0-terminated113#[no_mangle]114pub unsafe extern "C" fn jsonnet_jpath_add(vm: &State, v: *const c_char) {115	let cstr = CStr::from_ptr(v);116	let path = PathBuf::from(cstr.to_str().unwrap());117	let any_resolver = vm.import_resolver();118	let resolver = any_resolver119		.as_any()120		.downcast_ref::<FileImportResolver>()121		.expect("jpaths are not compatible with callback imports!");122	resolver.add_jpath(path);123}