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

difftreelog

source

bindings/jsonnet/src/import.rs3.1 KiBsourcehistory
1//! Import resolution manipulation utilities23use std::{4	alloc::Layout,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	bail,16	error::{ErrorKind::*, Result},17	ImportResolver,18};19use jrsonnet_gcmodule::Acyclic;20use jrsonnet_parser::{SourceDirectory, SourceFile, SourcePath};2122use crate::VM;2324pub type JsonnetImportCallback = unsafe extern "C" fn(25	ctx: *mut c_void,26	base: *const c_char,27	rel: *const c_char,28	found_here: *mut *const c_char,29	buf: *mut *mut c_char,30	buflen: *mut usize,31) -> c_int;3233/// Resolves imports using callback34#[derive(Acyclic)]35pub struct CallbackImportResolver {36	cb: JsonnetImportCallback,37	ctx: *mut c_void,38	out: RefCell<HashMap<SourcePath, Vec<u8>>>,39}40impl ImportResolver for CallbackImportResolver {41	fn resolve_from(&self, from: &SourcePath, path: &str) -> Result<SourcePath> {42		let base = if let Some(p) = from.downcast_ref::<SourceFile>() {43			let mut o = p.path().to_owned();44			o.pop();45			o46		} else if let Some(d) = from.downcast_ref::<SourceDirectory>() {47			d.path().to_owned()48		} else if from.is_default() {49			current_dir().map_err(|e| ImportIo(e.to_string()))?50		} else {51			unreachable!("can't resolve this path");52		};53		let base = unsafe { crate::unparse_path(&base) };54		let rel = CString::new(path).unwrap();55		let found_here: *mut c_char = null_mut();5657		let mut buf = null_mut();58		let mut buf_len = 0;59		let success = unsafe {60			(self.cb)(61				self.ctx,62				base.as_ptr(),63				rel.as_ptr(),64				&mut found_here.cast_const(),65				&mut buf,66				&mut buf_len,67			)68		};69		let buf_slice: &[u8] = unsafe { std::slice::from_raw_parts(buf.cast(), buf_len) };70		unsafe {71			std::alloc::dealloc(72				buf.cast(),73				Layout::from_size_align(buf_len, 1).expect("layout is valid"),74			);75		};76		let buf_intern = buf_slice.to_vec();7778		assert!(success == 0 || success == 1);79		if success == 0 {80			let result = String::from_utf8(buf_intern).expect("error should be valid string");81			bail!(ImportCallbackError(result));82		}8384		let found_here_raw = unsafe { CStr::from_ptr(found_here) };85		let found_here_buf = SourcePath::new(SourceFile::new(PathBuf::from(86			found_here_raw.to_str().unwrap(),87		)));88		unsafe {89			let _ = CString::from_raw(found_here);90		}9192		let mut out = self.out.borrow_mut();93		if !out.contains_key(&found_here_buf) {94			out.insert(found_here_buf.clone(), buf_intern);95		}9697		Ok(found_here_buf)98	}99	fn load_file_contents(&self, resolved: &SourcePath) -> Result<Vec<u8>> {100		Ok(self.out.borrow().get(resolved).unwrap().clone())101	}102}103104/// # Safety105///106/// It should be safe to call `cb` using valid values with passed `ctx`107#[no_mangle]108pub unsafe extern "C" fn jsonnet_import_callback(109	vm: &VM,110	cb: JsonnetImportCallback,111	ctx: *mut c_void,112) {113	vm.replace_import_resolver(CallbackImportResolver {114		cb,115		ctx,116		out: RefCell::new(HashMap::new()),117	});118}119120/// # Safety121///122/// `path` should be a NUL-terminated string123#[no_mangle]124pub unsafe extern "C" fn jsonnet_jpath_add(vm: &VM, path: *const c_char) {125	let cstr = unsafe { CStr::from_ptr(path) };126	let path = PathBuf::from(cstr.to_str().unwrap());127	vm.add_jpath(path);128}