123use std::{4 alloc::Layout,5 any::Any,6 cell::RefCell,7 collections::HashMap,8 env::current_dir,9 ffi::{c_void, CStr, CString},10 os::raw::{c_char, c_int},11 path::PathBuf,12 ptr::null_mut,13};1415use jrsonnet_evaluator::{16 bail,17 error::{ErrorKind::*, Result},18 ImportResolver,19};20use jrsonnet_gcmodule::Trace;21use jrsonnet_parser::{SourceDirectory, SourceFile, SourcePath};2223use crate::VM;2425pub type JsonnetImportCallback = unsafe extern "C" fn(26 ctx: *mut c_void,27 base: *const c_char,28 rel: *const c_char,29 found_here: *mut *const c_char,30 buf: *mut *mut c_char,31 buflen: *mut usize,32) -> c_int;333435#[derive(Trace)]36pub struct CallbackImportResolver {37 #[trace(skip)]38 cb: JsonnetImportCallback,39 #[trace(skip)]40 ctx: *mut c_void,41 out: RefCell<HashMap<SourcePath, Vec<u8>>>,42}43impl ImportResolver for CallbackImportResolver {44 fn resolve_from(&self, from: &SourcePath, path: &str) -> Result<SourcePath> {45 let base = if let Some(p) = from.downcast_ref::<SourceFile>() {46 let mut o = p.path().to_owned();47 o.pop();48 o49 } else if let Some(d) = from.downcast_ref::<SourceDirectory>() {50 d.path().to_owned()51 } else if from.is_default() {52 current_dir().map_err(|e| ImportIo(e.to_string()))?53 } else {54 unreachable!("can't resolve this path");55 };56 let base = unsafe { crate::unparse_path(&base) };57 let rel = CString::new(path).unwrap();58 let found_here: *mut c_char = null_mut();5960 let mut buf = null_mut();61 let mut buf_len = 0;62 let success = unsafe {63 (self.cb)(64 self.ctx,65 base.as_ptr(),66 rel.as_ptr(),67 &mut found_here.cast_const(),68 &mut buf,69 &mut buf_len,70 )71 };72 let buf_slice: &[u8] = unsafe { std::slice::from_raw_parts(buf.cast(), buf_len) };73 unsafe {74 std::alloc::dealloc(75 buf.cast(),76 Layout::from_size_align(buf_len, 1).expect("layout is valid"),77 );78 };79 let buf_intern = buf_slice.to_vec();8081 assert!(success == 0 || success == 1);82 if success == 0 {83 let result = String::from_utf8(buf_intern).expect("error should be valid string");84 bail!(ImportCallbackError(result));85 }8687 let found_here_raw = unsafe { CStr::from_ptr(found_here) };88 let found_here_buf = SourcePath::new(SourceFile::new(PathBuf::from(89 found_here_raw.to_str().unwrap(),90 )));91 unsafe {92 let _ = CString::from_raw(found_here);93 }9495 let mut out = self.out.borrow_mut();96 if !out.contains_key(&found_here_buf) {97 out.insert(found_here_buf.clone(), buf_intern);98 }99100 Ok(found_here_buf)101 }102 fn load_file_contents(&self, resolved: &SourcePath) -> Result<Vec<u8>> {103 Ok(self.out.borrow().get(resolved).unwrap().clone())104 }105106 fn as_any(&self) -> &dyn Any {107 self108 }109110 fn as_any_mut(&mut self) -> &mut dyn Any {111 self112 }113}114115116117118#[no_mangle]119pub unsafe extern "C" fn jsonnet_import_callback(120 vm: &VM,121 cb: JsonnetImportCallback,122 ctx: *mut c_void,123) {124 vm.replace_import_resolver(CallbackImportResolver {125 cb,126 ctx,127 out: RefCell::new(HashMap::new()),128 });129}130131132133134#[no_mangle]135pub unsafe extern "C" fn jsonnet_jpath_add(vm: &VM, path: *const c_char) {136 let cstr = unsafe { CStr::from_ptr(path) };137 let path = PathBuf::from(cstr.to_str().unwrap());138 vm.add_jpath(path);139}