difftreelog
feat(bindings) max stack
in: master
1 file changed
bindings/jsonnet/src/lib.rsdiffbeforeafterboth1use 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 jsonnet_version() -> &'static [u8; 8] {21 b"v0.16.0\0"22}2324#[derive(Default)]25struct NativeImportResolver {26 library_paths: RefCell<Vec<PathBuf>>,27}28impl NativeImportResolver {29 fn add_jpath(&self, path: PathBuf) {30 self.library_paths.borrow_mut().push(path);31 }32}33impl ImportResolver for NativeImportResolver {34 fn resolve_file(&self, from: &PathBuf, path: &PathBuf) -> Result<Rc<PathBuf>> {35 let mut new_path = from.clone();36 new_path.push(path);37 if new_path.exists() {38 Ok(Rc::new(new_path))39 } else {40 for library_path in self.library_paths.borrow().iter() {41 let mut cloned = library_path.clone();42 cloned.push(path);43 if cloned.exists() {44 return Ok(Rc::new(cloned));45 }46 }47 create_error_result(Error::ImportFileNotFound(from.clone(), path.clone()))48 }49 }50 fn load_file_contents(&self, id: &PathBuf) -> Result<Rc<str>> {51 let mut file =52 File::open(id).map_err(|_e| create_error(Error::ResolvedFileNotFound(id.clone())))?;53 let mut out = String::new();54 file.read_to_string(&mut out)55 .map_err(|_e| create_error(Error::ImportBadFileUtf8(id.clone())))?;56 Ok(out.into())57 }58 unsafe fn as_any(&self) -> &dyn Any {59 self60 }61}6263#[no_mangle]64pub extern "C" fn jsonnet_make() -> Box<EvaluationState> {65 let state = EvaluationState::default();66 state.with_stdlib();67 state.set_import_resolver(Box::new(NativeImportResolver::default()));68 Box::new(state)69}7071// TODO72#[no_mangle]73pub extern "C" fn jsonnet_max_stack(_vm: &EvaluationState, _v: c_uint) {}7475// jrsonnet currently have no GC, so these functions is no-op76#[no_mangle]77pub extern "C" fn jsonnet_gc_min_objects(_vm: &EvaluationState, _v: c_uint) {}78#[no_mangle]79pub extern "C" fn jsonnet_gc_growth_trigger(_vm: &EvaluationState, _v: c_double) {}8081// TODO82#[no_mangle]83pub extern "C" fn jsonnet_string_output(_vm: &EvaluationState, _v: c_int) {}8485#[no_mangle]86pub extern "C" fn jsonnet_json_extract_string(_vm: &EvaluationState, v: &Val) -> *mut c_char {87 match v.unwrap_if_lazy().unwrap() {88 Val::Str(s) => CString::new(&*s as &str).unwrap().into_raw(),89 _ => std::ptr::null_mut(),90 }91}92#[no_mangle]93pub extern "C" fn jsonnet_json_extract_number(94 _vm: &EvaluationState,95 v: &Val,96 out: &mut c_double,97) -> c_int {98 match v.unwrap_if_lazy().unwrap() {99 Val::Num(n) => {100 *out = n;101 1102 }103 _ => 0,104 }105}106#[no_mangle]107pub extern "C" fn jsonnet_json_extract_bool(_vm: &EvaluationState, v: &Val) -> c_int {108 match v.unwrap_if_lazy().unwrap() {109 Val::Bool(false) => 0,110 Val::Bool(true) => 1,111 _ => 2,112 }113}114#[no_mangle]115pub extern "C" fn jsonnet_json_extract_null(_vm: &EvaluationState, v: &Val) -> c_int {116 match v.unwrap_if_lazy().unwrap() {117 Val::Null => 1,118 _ => 0,119 }120}121122/// # Safety123///124/// This function is safe, if received v is a pointer to normal C string125#[no_mangle]126pub unsafe extern "C" fn jsonnet_json_make_string(127 _vm: &EvaluationState,128 v: *const c_char,129) -> Box<Val> {130 let cstr = CStr::from_ptr(v);131 let str = cstr.to_str().unwrap();132 Box::new(Val::Str(str.into()))133}134135#[no_mangle]136pub extern "C" fn jsonnet_json_make_number(_vm: &EvaluationState, v: c_double) -> Box<Val> {137 Box::new(Val::Num(v))138}139140#[no_mangle]141pub extern "C" fn jsonnet_json_make_bool(_vm: &EvaluationState, v: c_int) -> Box<Val> {142 assert!(v == 0 || v == 1);143 Box::new(Val::Bool(v == 1))144}145146#[no_mangle]147pub extern "C" fn jsonnet_json_make_null(_vm: &EvaluationState) -> Box<Val> {148 Box::new(Val::Null)149}150151#[no_mangle]152pub extern "C" fn jsonnet_json_make_array(_vm: &EvaluationState) -> Box<Val> {153 Box::new(Val::Arr(Rc::new(Vec::new())))154}155156#[no_mangle]157pub extern "C" fn jsonnet_json_array_append(_vm: &EvaluationState, arr: &mut Val, val: &Val) {158 match arr {159 Val::Arr(old) => {160 // TODO: Mutate array, instead of recreating them161 let mut new = Vec::new();162 new.extend(old.iter().cloned());163 new.push(val.clone());164 *arr = Val::Arr(Rc::new(new));165 }166 _ => panic!("should receive array"),167 }168}169170#[no_mangle]171pub extern "C" fn jsonnet_json_make_object(_vm: &EvaluationState) -> Box<Val> {172 Box::new(Val::Obj(ObjValue::new_empty()))173}174175/// # Safety176///177/// This function is safe if passed name is ok178#[no_mangle]179pub unsafe extern "C" fn jsonnet_json_object_append(180 _vm: &EvaluationState,181 obj: &mut Val,182 name: *const c_char,183 val: &Val,184) {185 match obj {186 Val::Obj(old) => {187 let mut new = BTreeMap::new();188 new.insert(189 CStr::from_ptr(name).to_str().unwrap().into(),190 ObjMember {191 add: false,192 visibility: Visibility::Normal,193 invoke: LazyBinding::Bound(LazyVal::new_resolved(val.clone())),194 },195 );196 let new_obj = ObjValue::new(Some(old.clone()), Rc::new(new));197 *obj = Val::Obj(new_obj);198 }199 _ => panic!("should receive array"),200 }201}202203/// # Safety204///205/// This function is most definitely broken, but it works somehow, see TODO inside206#[no_mangle]207pub unsafe extern "C" fn jsonnet_realloc(208 _vm: &EvaluationState,209 buf: *mut u8,210 sz: usize,211) -> *mut u8 {212 if buf.is_null() {213 assert!(sz != 0);214 return std::alloc::alloc(Layout::from_size_align(sz, std::mem::align_of::<u8>()).unwrap());215 }216 // TODO: Somehow store size of allocation, because its real size is probally not 16 :D217 // OR (Alternative way of fixing this TODO)218 // TODO: Standard allocator uses malloc, and it doesn't uses allocation size,219 // TODO: so it should work in normal cases. Maybe force allocator for this library?220 let old_layout = Layout::from_size_align(16, std::mem::align_of::<u8>()).unwrap();221 if sz == 0 {222 std::alloc::dealloc(buf, old_layout);223 return std::ptr::null_mut();224 }225 std::alloc::realloc(buf, old_layout, sz)226}227228#[no_mangle]229#[allow(clippy::boxed_local)]230pub extern "C" fn jsonnet_json_destroy(_vm: &EvaluationState, _v: Box<Val>) {}231232#[no_mangle]233pub extern "C" fn jsonnet_import_callback() {234 todo!()235}236#[no_mangle]237pub extern "C" fn jsonnet_native_callback() {238 todo!()239}240#[no_mangle]241pub extern "C" fn jsonnet_ext_var() {242 todo!()243}244#[no_mangle]245pub extern "C" fn jsonnet_ext_code() {246 todo!()247}248#[no_mangle]249pub extern "C" fn jsonnet_tla_var() {250 todo!()251}252#[no_mangle]253pub extern "C" fn jsonnet_tla_code() {254 todo!()255}256#[no_mangle]257pub extern "C" fn jsonnet_max_trace() {258 todo!()259}260261/// # Safety262///263/// This function is safe, if received v is a pointer to normal C string264#[no_mangle]265pub unsafe extern "C" fn jsonnet_jpath_add(vm: &EvaluationState, v: *const c_char) {266 let cstr = CStr::from_ptr(v);267 let path = PathBuf::from(cstr.to_str().unwrap());268 let any_resolver = vm.import_resolver();269 let resolver = any_resolver270 .as_any()271 .downcast_ref::<NativeImportResolver>()272 .unwrap();273 resolver.add_jpath(path);274}275276/// # Safety277///278/// This function is safe, if received v is a pointer to normal C string279#[no_mangle]280pub unsafe extern "C" fn jsonnet_evaluate_file(281 vm: &EvaluationState,282 filename: *const c_char,283 error: &mut c_int,284) -> *const c_char {285 vm.run_in_state(|| {286 use std::fmt::Write;287 let filename = CStr::from_ptr(filename);288 match vm.evaluate_file_to_json(&PathBuf::from(filename.to_str().unwrap())) {289 Ok(v) => {290 *error = 0;291 CString::new(&*v as &str).unwrap().into_raw()292 }293 Err(e) => {294 *error = 1;295 let mut out = String::new();296 writeln!(out, "{:?}", e.0).unwrap();297 for i in (e.1).0.iter() {298 writeln!(out, "{:?}", i).unwrap();299 }300 CString::new(&out as &str).unwrap().into_raw()301 }302 }303 })304}305#[no_mangle]306pub extern "C" fn jsonnet_evaluate_snippet() {307 todo!()308}309#[no_mangle]310pub extern "C" fn jsonnet_evaluate_file_multi() {311 todo!()312}313#[no_mangle]314pub extern "C" fn jsonnet_evaluate_snippet_multi() {315 todo!()316}317#[no_mangle]318pub extern "C" fn jsonnet_evaluate_file_stream() {319 todo!()320}321#[no_mangle]322pub extern "C" fn jsonnet_evaluate_snippet_stream() {323 todo!()324}325326#[no_mangle]327#[allow(clippy::boxed_local)]328pub extern "C" fn jsonnet_destroy(_vm: Box<EvaluationState>) {}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 jsonnet_version() -> &'static [u8; 8] {21 b"v0.16.0\0"22}2324#[derive(Default)]25struct NativeImportResolver {26 library_paths: RefCell<Vec<PathBuf>>,27}28impl NativeImportResolver {29 fn add_jpath(&self, path: PathBuf) {30 self.library_paths.borrow_mut().push(path);31 }32}33impl ImportResolver for NativeImportResolver {34 fn resolve_file(&self, from: &PathBuf, path: &PathBuf) -> Result<Rc<PathBuf>> {35 let mut new_path = from.clone();36 new_path.push(path);37 if new_path.exists() {38 Ok(Rc::new(new_path))39 } else {40 for library_path in self.library_paths.borrow().iter() {41 let mut cloned = library_path.clone();42 cloned.push(path);43 if cloned.exists() {44 return Ok(Rc::new(cloned));45 }46 }47 create_error_result(Error::ImportFileNotFound(from.clone(), path.clone()))48 }49 }50 fn load_file_contents(&self, id: &PathBuf) -> Result<Rc<str>> {51 let mut file =52 File::open(id).map_err(|_e| create_error(Error::ResolvedFileNotFound(id.clone())))?;53 let mut out = String::new();54 file.read_to_string(&mut out)55 .map_err(|_e| create_error(Error::ImportBadFileUtf8(id.clone())))?;56 Ok(out.into())57 }58 unsafe fn as_any(&self) -> &dyn Any {59 self60 }61}6263#[no_mangle]64pub extern "C" fn jsonnet_make() -> Box<EvaluationState> {65 let state = EvaluationState::default();66 state.with_stdlib();67 state.set_import_resolver(Box::new(NativeImportResolver::default()));68 Box::new(state)69}7071#[no_mangle]72pub extern "C" fn jsonnet_max_stack(vm: &EvaluationState, v: c_uint) {73 vm.set_max_stack(v as usize);74}7576// jrsonnet currently have no GC, so these functions is no-op77#[no_mangle]78pub extern "C" fn jsonnet_gc_min_objects(_vm: &EvaluationState, _v: c_uint) {}79#[no_mangle]80pub extern "C" fn jsonnet_gc_growth_trigger(_vm: &EvaluationState, _v: c_double) {}8182// TODO83#[no_mangle]84pub extern "C" fn jsonnet_string_output(_vm: &EvaluationState, _v: c_int) {}8586#[no_mangle]87pub extern "C" fn jsonnet_json_extract_string(_vm: &EvaluationState, v: &Val) -> *mut c_char {88 match v.unwrap_if_lazy().unwrap() {89 Val::Str(s) => CString::new(&*s as &str).unwrap().into_raw(),90 _ => std::ptr::null_mut(),91 }92}93#[no_mangle]94pub extern "C" fn jsonnet_json_extract_number(95 _vm: &EvaluationState,96 v: &Val,97 out: &mut c_double,98) -> c_int {99 match v.unwrap_if_lazy().unwrap() {100 Val::Num(n) => {101 *out = n;102 1103 }104 _ => 0,105 }106}107#[no_mangle]108pub extern "C" fn jsonnet_json_extract_bool(_vm: &EvaluationState, v: &Val) -> c_int {109 match v.unwrap_if_lazy().unwrap() {110 Val::Bool(false) => 0,111 Val::Bool(true) => 1,112 _ => 2,113 }114}115#[no_mangle]116pub extern "C" fn jsonnet_json_extract_null(_vm: &EvaluationState, v: &Val) -> c_int {117 match v.unwrap_if_lazy().unwrap() {118 Val::Null => 1,119 _ => 0,120 }121}122123/// # Safety124///125/// This function is safe, if received v is a pointer to normal C string126#[no_mangle]127pub unsafe extern "C" fn jsonnet_json_make_string(128 _vm: &EvaluationState,129 v: *const c_char,130) -> Box<Val> {131 let cstr = CStr::from_ptr(v);132 let str = cstr.to_str().unwrap();133 Box::new(Val::Str(str.into()))134}135136#[no_mangle]137pub extern "C" fn jsonnet_json_make_number(_vm: &EvaluationState, v: c_double) -> Box<Val> {138 Box::new(Val::Num(v))139}140141#[no_mangle]142pub extern "C" fn jsonnet_json_make_bool(_vm: &EvaluationState, v: c_int) -> Box<Val> {143 assert!(v == 0 || v == 1);144 Box::new(Val::Bool(v == 1))145}146147#[no_mangle]148pub extern "C" fn jsonnet_json_make_null(_vm: &EvaluationState) -> Box<Val> {149 Box::new(Val::Null)150}151152#[no_mangle]153pub extern "C" fn jsonnet_json_make_array(_vm: &EvaluationState) -> Box<Val> {154 Box::new(Val::Arr(Rc::new(Vec::new())))155}156157#[no_mangle]158pub extern "C" fn jsonnet_json_array_append(_vm: &EvaluationState, arr: &mut Val, val: &Val) {159 match arr {160 Val::Arr(old) => {161 // TODO: Mutate array, instead of recreating them162 let mut new = Vec::new();163 new.extend(old.iter().cloned());164 new.push(val.clone());165 *arr = Val::Arr(Rc::new(new));166 }167 _ => panic!("should receive array"),168 }169}170171#[no_mangle]172pub extern "C" fn jsonnet_json_make_object(_vm: &EvaluationState) -> Box<Val> {173 Box::new(Val::Obj(ObjValue::new_empty()))174}175176/// # Safety177///178/// This function is safe if passed name is ok179#[no_mangle]180pub unsafe extern "C" fn jsonnet_json_object_append(181 _vm: &EvaluationState,182 obj: &mut Val,183 name: *const c_char,184 val: &Val,185) {186 match obj {187 Val::Obj(old) => {188 let mut new = BTreeMap::new();189 new.insert(190 CStr::from_ptr(name).to_str().unwrap().into(),191 ObjMember {192 add: false,193 visibility: Visibility::Normal,194 invoke: LazyBinding::Bound(LazyVal::new_resolved(val.clone())),195 },196 );197 let new_obj = ObjValue::new(Some(old.clone()), Rc::new(new));198 *obj = Val::Obj(new_obj);199 }200 _ => panic!("should receive array"),201 }202}203204/// # Safety205///206/// This function is most definitely broken, but it works somehow, see TODO inside207#[no_mangle]208pub unsafe extern "C" fn jsonnet_realloc(209 _vm: &EvaluationState,210 buf: *mut u8,211 sz: usize,212) -> *mut u8 {213 if buf.is_null() {214 assert!(sz != 0);215 return std::alloc::alloc(Layout::from_size_align(sz, std::mem::align_of::<u8>()).unwrap());216 }217 // TODO: Somehow store size of allocation, because its real size is probally not 16 :D218 // OR (Alternative way of fixing this TODO)219 // TODO: Standard allocator uses malloc, and it doesn't uses allocation size,220 // TODO: so it should work in normal cases. Maybe force allocator for this library?221 let old_layout = Layout::from_size_align(16, std::mem::align_of::<u8>()).unwrap();222 if sz == 0 {223 std::alloc::dealloc(buf, old_layout);224 return std::ptr::null_mut();225 }226 std::alloc::realloc(buf, old_layout, sz)227}228229#[no_mangle]230#[allow(clippy::boxed_local)]231pub extern "C" fn jsonnet_json_destroy(_vm: &EvaluationState, _v: Box<Val>) {}232233#[no_mangle]234pub extern "C" fn jsonnet_import_callback() {235 todo!()236}237#[no_mangle]238pub extern "C" fn jsonnet_native_callback() {239 todo!()240}241#[no_mangle]242pub extern "C" fn jsonnet_ext_var() {243 todo!()244}245#[no_mangle]246pub extern "C" fn jsonnet_ext_code() {247 todo!()248}249#[no_mangle]250pub extern "C" fn jsonnet_tla_var() {251 todo!()252}253#[no_mangle]254pub extern "C" fn jsonnet_tla_code() {255 todo!()256}257#[no_mangle]258pub extern "C" fn jsonnet_max_trace() {259 todo!()260}261262/// # Safety263///264/// This function is safe, if received v is a pointer to normal C string265#[no_mangle]266pub unsafe extern "C" fn jsonnet_jpath_add(vm: &EvaluationState, v: *const c_char) {267 let cstr = CStr::from_ptr(v);268 let path = PathBuf::from(cstr.to_str().unwrap());269 let any_resolver = vm.import_resolver();270 let resolver = any_resolver271 .as_any()272 .downcast_ref::<NativeImportResolver>()273 .unwrap();274 resolver.add_jpath(path);275}276277/// # Safety278///279/// This function is safe, if received v is a pointer to normal C string280#[no_mangle]281pub unsafe extern "C" fn jsonnet_evaluate_file(282 vm: &EvaluationState,283 filename: *const c_char,284 error: &mut c_int,285) -> *const c_char {286 vm.run_in_state(|| {287 use std::fmt::Write;288 let filename = CStr::from_ptr(filename);289 match vm.evaluate_file_to_json(&PathBuf::from(filename.to_str().unwrap())) {290 Ok(v) => {291 *error = 0;292 CString::new(&*v as &str).unwrap().into_raw()293 }294 Err(e) => {295 *error = 1;296 let mut out = String::new();297 writeln!(out, "{:?}", e.0).unwrap();298 for i in (e.1).0.iter() {299 writeln!(out, "{:?}", i).unwrap();300 }301 CString::new(&out as &str).unwrap().into_raw()302 }303 }304 })305}306#[no_mangle]307pub extern "C" fn jsonnet_evaluate_snippet() {308 todo!()309}310#[no_mangle]311pub extern "C" fn jsonnet_evaluate_file_multi() {312 todo!()313}314#[no_mangle]315pub extern "C" fn jsonnet_evaluate_snippet_multi() {316 todo!()317}318#[no_mangle]319pub extern "C" fn jsonnet_evaluate_file_stream() {320 todo!()321}322#[no_mangle]323pub extern "C" fn jsonnet_evaluate_snippet_stream() {324 todo!()325}326327#[no_mangle]328#[allow(clippy::boxed_local)]329pub extern "C" fn jsonnet_destroy(_vm: Box<EvaluationState>) {}