1use jrsonnet_evaluator::{2 create_error, create_error_result, Error, EvaluationState, ImportResolver, LazyBinding,3 LazyVal, ObjMember, ObjValue, Result, Val,4};5use jrsonnet_parser::Visibility;6use libc::{c_char, c_double, c_int, c_uint};7use std::{8 alloc::Layout,9 any::Any,10 cell::RefCell,11 collections::BTreeMap,12 ffi::{CStr, CString},13 fs::File,14 io::Read,15 path::PathBuf,16 rc::Rc,17};1819#[no_mangle]20pub extern "C" fn _start() {}2122#[no_mangle]23pub extern "C" fn jsonnet_version() -> &'static [u8; 8] {24 b"v0.16.0\0"25}2627#[derive(Default)]28struct NativeImportResolver {29 library_paths: RefCell<Vec<PathBuf>>,30}31impl NativeImportResolver {32 fn add_jpath(&self, path: PathBuf) {33 self.library_paths.borrow_mut().push(path);34 }35}36impl ImportResolver for NativeImportResolver {37 fn resolve_file(&self, from: &PathBuf, path: &PathBuf) -> Result<Rc<PathBuf>> {38 let mut new_path = from.clone();39 new_path.push(path);40 if new_path.exists() {41 Ok(Rc::new(new_path))42 } else {43 for library_path in self.library_paths.borrow().iter() {44 let mut cloned = library_path.clone();45 cloned.push(path);46 if cloned.exists() {47 return Ok(Rc::new(cloned));48 }49 }50 create_error_result(Error::ImportFileNotFound(from.clone(), path.clone()))51 }52 }53 fn load_file_contents(&self, id: &PathBuf) -> Result<Rc<str>> {54 let mut file =55 File::open(id).map_err(|_e| create_error(Error::ResolvedFileNotFound(id.clone())))?;56 let mut out = String::new();57 file.read_to_string(&mut out)58 .map_err(|_e| create_error(Error::ImportBadFileUtf8(id.clone())))?;59 Ok(out.into())60 }61 unsafe fn as_any(&self) -> &dyn Any {62 self63 }64}6566#[no_mangle]67pub extern "C" fn jsonnet_make() -> Box<EvaluationState> {68 let state = EvaluationState::default();69 state.with_stdlib();70 state.set_import_resolver(Box::new(NativeImportResolver::default()));71 Box::new(state)72}7374#[no_mangle]75pub extern "C" fn jsonnet_max_stack(vm: &EvaluationState, v: c_uint) {76 vm.set_max_stack(v as usize);77}787980#[no_mangle]81pub extern "C" fn jsonnet_gc_min_objects(_vm: &EvaluationState, _v: c_uint) {}82#[no_mangle]83pub extern "C" fn jsonnet_gc_growth_trigger(_vm: &EvaluationState, _v: c_double) {}848586#[no_mangle]87pub extern "C" fn jsonnet_string_output(_vm: &EvaluationState, _v: c_int) {}8889#[no_mangle]90pub extern "C" fn jsonnet_json_extract_string(_vm: &EvaluationState, v: &Val) -> *mut c_char {91 match v.unwrap_if_lazy().unwrap() {92 Val::Str(s) => CString::new(&*s as &str).unwrap().into_raw(),93 _ => std::ptr::null_mut(),94 }95}96#[no_mangle]97pub extern "C" fn jsonnet_json_extract_number(98 _vm: &EvaluationState,99 v: &Val,100 out: &mut c_double,101) -> c_int {102 match v.unwrap_if_lazy().unwrap() {103 Val::Num(n) => {104 *out = n;105 1106 }107 _ => 0,108 }109}110#[no_mangle]111pub extern "C" fn jsonnet_json_extract_bool(_vm: &EvaluationState, v: &Val) -> c_int {112 match v.unwrap_if_lazy().unwrap() {113 Val::Bool(false) => 0,114 Val::Bool(true) => 1,115 _ => 2,116 }117}118#[no_mangle]119pub extern "C" fn jsonnet_json_extract_null(_vm: &EvaluationState, v: &Val) -> c_int {120 match v.unwrap_if_lazy().unwrap() {121 Val::Null => 1,122 _ => 0,123 }124}125126127128129#[no_mangle]130pub unsafe extern "C" fn jsonnet_json_make_string(131 _vm: &EvaluationState,132 v: *const c_char,133) -> Box<Val> {134 let cstr = CStr::from_ptr(v);135 let str = cstr.to_str().unwrap();136 Box::new(Val::Str(str.into()))137}138139#[no_mangle]140pub extern "C" fn jsonnet_json_make_number(_vm: &EvaluationState, v: c_double) -> Box<Val> {141 Box::new(Val::Num(v))142}143144#[no_mangle]145pub extern "C" fn jsonnet_json_make_bool(_vm: &EvaluationState, v: c_int) -> Box<Val> {146 assert!(v == 0 || v == 1);147 Box::new(Val::Bool(v == 1))148}149150#[no_mangle]151pub extern "C" fn jsonnet_json_make_null(_vm: &EvaluationState) -> Box<Val> {152 Box::new(Val::Null)153}154155#[no_mangle]156pub extern "C" fn jsonnet_json_make_array(_vm: &EvaluationState) -> Box<Val> {157 Box::new(Val::Arr(Rc::new(Vec::new())))158}159160#[no_mangle]161pub extern "C" fn jsonnet_json_array_append(_vm: &EvaluationState, arr: &mut Val, val: &Val) {162 match arr {163 Val::Arr(old) => {164 165 let mut new = Vec::new();166 new.extend(old.iter().cloned());167 new.push(val.clone());168 *arr = Val::Arr(Rc::new(new));169 }170 _ => panic!("should receive array"),171 }172}173174#[no_mangle]175pub extern "C" fn jsonnet_json_make_object(_vm: &EvaluationState) -> Box<Val> {176 Box::new(Val::Obj(ObjValue::new_empty()))177}178179180181182#[no_mangle]183pub unsafe extern "C" fn jsonnet_json_object_append(184 _vm: &EvaluationState,185 obj: &mut Val,186 name: *const c_char,187 val: &Val,188) {189 match obj {190 Val::Obj(old) => {191 let mut new = BTreeMap::new();192 new.insert(193 CStr::from_ptr(name).to_str().unwrap().into(),194 ObjMember {195 add: false,196 visibility: Visibility::Normal,197 invoke: LazyBinding::Bound(LazyVal::new_resolved(val.clone())),198 },199 );200 let new_obj = ObjValue::new(Some(old.clone()), Rc::new(new));201 *obj = Val::Obj(new_obj);202 }203 _ => panic!("should receive array"),204 }205}206207208209210#[no_mangle]211pub unsafe extern "C" fn jsonnet_realloc(212 _vm: &EvaluationState,213 buf: *mut u8,214 sz: usize,215) -> *mut u8 {216 if buf.is_null() {217 assert!(sz != 0);218 return std::alloc::alloc(Layout::from_size_align(sz, std::mem::align_of::<u8>()).unwrap());219 }220 221 222 223 224 let old_layout = Layout::from_size_align(16, std::mem::align_of::<u8>()).unwrap();225 if sz == 0 {226 std::alloc::dealloc(buf, old_layout);227 return std::ptr::null_mut();228 }229 std::alloc::realloc(buf, old_layout, sz)230}231232#[no_mangle]233#[allow(clippy::boxed_local)]234pub extern "C" fn jsonnet_json_destroy(_vm: &EvaluationState, _v: Box<Val>) {}235236#[no_mangle]237pub extern "C" fn jsonnet_import_callback() {238 todo!()239}240#[no_mangle]241pub extern "C" fn jsonnet_native_callback() {242 todo!()243}244#[no_mangle]245pub extern "C" fn jsonnet_ext_var() {246 todo!()247}248#[no_mangle]249pub extern "C" fn jsonnet_ext_code() {250 todo!()251}252#[no_mangle]253pub extern "C" fn jsonnet_tla_var() {254 todo!()255}256#[no_mangle]257pub extern "C" fn jsonnet_tla_code() {258 todo!()259}260#[no_mangle]261pub extern "C" fn jsonnet_max_trace() {262 todo!()263}264265266267268#[no_mangle]269pub unsafe extern "C" fn jsonnet_jpath_add(vm: &EvaluationState, v: *const c_char) {270 let cstr = CStr::from_ptr(v);271 let path = PathBuf::from(cstr.to_str().unwrap());272 let any_resolver = vm.import_resolver();273 let resolver = any_resolver274 .as_any()275 .downcast_ref::<NativeImportResolver>()276 .unwrap();277 resolver.add_jpath(path);278}279280281282283#[no_mangle]284pub unsafe extern "C" fn jsonnet_evaluate_file(285 vm: &EvaluationState,286 filename: *const c_char,287 error: &mut c_int,288) -> *const c_char {289 vm.run_in_state(|| {290 use std::fmt::Write;291 let filename = CStr::from_ptr(filename);292 match vm.evaluate_file_to_json(&PathBuf::from(filename.to_str().unwrap())) {293 Ok(v) => {294 *error = 0;295 CString::new(&*v as &str).unwrap().into_raw()296 }297 Err(e) => {298 *error = 1;299 let mut out = String::new();300 writeln!(out, "{:?}", e.0).unwrap();301 for i in (e.1).0.iter() {302 writeln!(out, "{:?}", i).unwrap();303 }304 CString::new(&out as &str).unwrap().into_raw()305 }306 }307 })308}309310311312313#[no_mangle]314pub unsafe extern "C" fn jsonnet_evaluate_snippet(315 vm: &EvaluationState,316 filename: *const c_char,317 snippet: *const c_char,318 error: &mut c_int,319) -> *const c_char {320 vm.run_in_state(|| {321 use std::fmt::Write;322 let filename = CStr::from_ptr(filename);323 let snippet = CStr::from_ptr(snippet);324 match vm.evaluate_snippet_to_json(325 &PathBuf::from(filename.to_str().unwrap()),326 &snippet.to_str().unwrap(),327 ) {328 Ok(v) => {329 *error = 0;330 CString::new(&*v as &str).unwrap().into_raw()331 }332 Err(e) => {333 *error = 1;334 let mut out = String::new();335 writeln!(out, "{:?}", e.0).unwrap();336 for i in (e.1).0.iter() {337 writeln!(out, "{:?} ---- {}", i.0, i.1).unwrap();338 }339 CString::new(&out as &str).unwrap().into_raw()340 }341 }342 })343}344345#[no_mangle]346pub extern "C" fn jsonnet_evaluate_file_multi() {347 todo!()348}349#[no_mangle]350pub extern "C" fn jsonnet_evaluate_snippet_multi() {351 todo!()352}353#[no_mangle]354pub extern "C" fn jsonnet_evaluate_file_stream() {355 todo!()356}357#[no_mangle]358pub extern "C" fn jsonnet_evaluate_snippet_stream() {359 todo!()360}361362#[no_mangle]363#[allow(clippy::boxed_local)]364pub extern "C" fn jsonnet_destroy(_vm: Box<EvaluationState>) {}