git.delta.rocks / jrsonnet / refs/commits / 516792f0f249

difftreelog

source

bindings/jsonnet/src/lib.rs8.9 KiBsourcehistory
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]20#[cfg(target = "wasm32-wasi")]21pub extern "C" fn _start() {}2223#[no_mangle]24pub extern "C" fn jsonnet_version() -> &'static [u8; 8] {25	b"v0.16.0\0"26}2728#[derive(Default)]29struct NativeImportResolver {30	library_paths: RefCell<Vec<PathBuf>>,31}32impl NativeImportResolver {33	fn add_jpath(&self, path: PathBuf) {34		self.library_paths.borrow_mut().push(path);35	}36}37impl ImportResolver for NativeImportResolver {38	fn resolve_file(&self, from: &PathBuf, path: &PathBuf) -> Result<Rc<PathBuf>> {39		let mut new_path = from.clone();40		new_path.push(path);41		if new_path.exists() {42			Ok(Rc::new(new_path))43		} else {44			for library_path in self.library_paths.borrow().iter() {45				let mut cloned = library_path.clone();46				cloned.push(path);47				if cloned.exists() {48					return Ok(Rc::new(cloned));49				}50			}51			create_error_result(Error::ImportFileNotFound(from.clone(), path.clone()))52		}53	}54	fn load_file_contents(&self, id: &PathBuf) -> Result<Rc<str>> {55		let mut file =56			File::open(id).map_err(|_e| create_error(Error::ResolvedFileNotFound(id.clone())))?;57		let mut out = String::new();58		file.read_to_string(&mut out)59			.map_err(|_e| create_error(Error::ImportBadFileUtf8(id.clone())))?;60		Ok(out.into())61	}62	unsafe fn as_any(&self) -> &dyn Any {63		self64	}65}6667#[no_mangle]68pub extern "C" fn jsonnet_make() -> Box<EvaluationState> {69	let state = EvaluationState::default();70	state.with_stdlib();71	state.set_import_resolver(Box::new(NativeImportResolver::default()));72	Box::new(state)73}7475#[no_mangle]76pub extern "C" fn jsonnet_max_stack(vm: &EvaluationState, v: c_uint) {77	vm.set_max_stack(v as usize);78}7980// jrsonnet currently have no GC, so these functions is no-op81#[no_mangle]82pub extern "C" fn jsonnet_gc_min_objects(_vm: &EvaluationState, _v: c_uint) {}83#[no_mangle]84pub extern "C" fn jsonnet_gc_growth_trigger(_vm: &EvaluationState, _v: c_double) {}8586// TODO87#[no_mangle]88pub extern "C" fn jsonnet_string_output(_vm: &EvaluationState, _v: c_int) {89	todo!()90}9192#[no_mangle]93pub extern "C" fn jsonnet_json_extract_string(_vm: &EvaluationState, v: &Val) -> *mut c_char {94	match v.unwrap_if_lazy().unwrap() {95		Val::Str(s) => CString::new(&*s as &str).unwrap().into_raw(),96		_ => std::ptr::null_mut(),97	}98}99#[no_mangle]100pub extern "C" fn jsonnet_json_extract_number(101	_vm: &EvaluationState,102	v: &Val,103	out: &mut c_double,104) -> c_int {105	match v.unwrap_if_lazy().unwrap() {106		Val::Num(n) => {107			*out = n;108			1109		}110		_ => 0,111	}112}113#[no_mangle]114pub extern "C" fn jsonnet_json_extract_bool(_vm: &EvaluationState, v: &Val) -> c_int {115	match v.unwrap_if_lazy().unwrap() {116		Val::Bool(false) => 0,117		Val::Bool(true) => 1,118		_ => 2,119	}120}121#[no_mangle]122pub extern "C" fn jsonnet_json_extract_null(_vm: &EvaluationState, v: &Val) -> c_int {123	match v.unwrap_if_lazy().unwrap() {124		Val::Null => 1,125		_ => 0,126	}127}128129/// # Safety130///131/// This function is safe, if received v is a pointer to normal C string132#[no_mangle]133pub unsafe extern "C" fn jsonnet_json_make_string(134	_vm: &EvaluationState,135	v: *const c_char,136) -> Box<Val> {137	let cstr = CStr::from_ptr(v);138	let str = cstr.to_str().unwrap();139	Box::new(Val::Str(str.into()))140}141142#[no_mangle]143pub extern "C" fn jsonnet_json_make_number(_vm: &EvaluationState, v: c_double) -> Box<Val> {144	Box::new(Val::Num(v))145}146147#[no_mangle]148pub extern "C" fn jsonnet_json_make_bool(_vm: &EvaluationState, v: c_int) -> Box<Val> {149	assert!(v == 0 || v == 1);150	Box::new(Val::Bool(v == 1))151}152153#[no_mangle]154pub extern "C" fn jsonnet_json_make_null(_vm: &EvaluationState) -> Box<Val> {155	Box::new(Val::Null)156}157158#[no_mangle]159pub extern "C" fn jsonnet_json_make_array(_vm: &EvaluationState) -> Box<Val> {160	Box::new(Val::Arr(Rc::new(Vec::new())))161}162163#[no_mangle]164pub extern "C" fn jsonnet_json_array_append(_vm: &EvaluationState, arr: &mut Val, val: &Val) {165	match arr {166		Val::Arr(old) => {167			// TODO: Mutate array, instead of recreating them168			let mut new = Vec::new();169			new.extend(old.iter().cloned());170			new.push(val.clone());171			*arr = Val::Arr(Rc::new(new));172		}173		_ => panic!("should receive array"),174	}175}176177#[no_mangle]178pub extern "C" fn jsonnet_json_make_object(_vm: &EvaluationState) -> Box<Val> {179	Box::new(Val::Obj(ObjValue::new_empty()))180}181182/// # Safety183///184/// This function is safe if passed name is ok185#[no_mangle]186pub unsafe extern "C" fn jsonnet_json_object_append(187	_vm: &EvaluationState,188	obj: &mut Val,189	name: *const c_char,190	val: &Val,191) {192	match obj {193		Val::Obj(old) => {194			let mut new = BTreeMap::new();195			new.insert(196				CStr::from_ptr(name).to_str().unwrap().into(),197				ObjMember {198					add: false,199					visibility: Visibility::Normal,200					invoke: LazyBinding::Bound(LazyVal::new_resolved(val.clone())),201				},202			);203			let new_obj = ObjValue::new(Some(old.clone()), Rc::new(new));204			*obj = Val::Obj(new_obj);205		}206		_ => panic!("should receive array"),207	}208}209210/// # Safety211///212/// This function is most definitely broken, but it works somehow, see TODO inside213#[no_mangle]214pub unsafe extern "C" fn jsonnet_realloc(215	_vm: &EvaluationState,216	buf: *mut u8,217	sz: usize,218) -> *mut u8 {219	if buf.is_null() {220		assert!(sz != 0);221		return std::alloc::alloc(Layout::from_size_align(sz, std::mem::align_of::<u8>()).unwrap());222	}223	// TODO: Somehow store size of allocation, because its real size is probally not 16 :D224	// OR (Alternative way of fixing this TODO)225	// TODO: Standard allocator uses malloc, and it doesn't uses allocation size,226	// TODO: so it should work in normal cases. Maybe force allocator for this library?227	let old_layout = Layout::from_size_align(16, std::mem::align_of::<u8>()).unwrap();228	if sz == 0 {229		std::alloc::dealloc(buf, old_layout);230		return std::ptr::null_mut();231	}232	std::alloc::realloc(buf, old_layout, sz)233}234235#[no_mangle]236#[allow(clippy::boxed_local)]237pub extern "C" fn jsonnet_json_destroy(_vm: &EvaluationState, _v: Box<Val>) {}238239#[no_mangle]240pub extern "C" fn jsonnet_import_callback() {241	todo!()242}243#[no_mangle]244pub extern "C" fn jsonnet_native_callback() {245	todo!()246}247#[no_mangle]248pub extern "C" fn jsonnet_ext_var() {249	todo!()250}251#[no_mangle]252pub extern "C" fn jsonnet_ext_code() {253	todo!()254}255#[no_mangle]256pub extern "C" fn jsonnet_tla_var() {257	todo!()258}259#[no_mangle]260pub extern "C" fn jsonnet_tla_code() {261	todo!()262}263#[no_mangle]264pub extern "C" fn jsonnet_max_trace() {265	todo!()266}267268/// # Safety269///270/// This function is safe, if received v is a pointer to normal C string271#[no_mangle]272pub unsafe extern "C" fn jsonnet_jpath_add(vm: &EvaluationState, v: *const c_char) {273	let cstr = CStr::from_ptr(v);274	let path = PathBuf::from(cstr.to_str().unwrap());275	let any_resolver = vm.import_resolver();276	let resolver = any_resolver277		.as_any()278		.downcast_ref::<NativeImportResolver>()279		.unwrap();280	resolver.add_jpath(path);281}282283/// # Safety284///285/// This function is safe, if received v is a pointer to normal C string286#[no_mangle]287pub unsafe extern "C" fn jsonnet_evaluate_file(288	vm: &EvaluationState,289	filename: *const c_char,290	error: &mut c_int,291) -> *const c_char {292	vm.run_in_state(|| {293		use std::fmt::Write;294		let filename = CStr::from_ptr(filename);295		match vm.evaluate_file_to_json(&PathBuf::from(filename.to_str().unwrap())) {296			Ok(v) => {297				*error = 0;298				CString::new(&*v as &str).unwrap().into_raw()299			}300			Err(e) => {301				*error = 1;302				let mut out = String::new();303				writeln!(out, "{:?}", e.0).unwrap();304				for i in (e.1).0.iter() {305					writeln!(out, "{:?}", i.0).unwrap();306				}307				CString::new(&out as &str).unwrap().into_raw()308			}309		}310	})311}312313/// # Safety314///315/// This function is safe, if received v is a pointer to normal C string316#[no_mangle]317pub unsafe extern "C" fn jsonnet_evaluate_snippet(318	vm: &EvaluationState,319	filename: *const c_char,320	snippet: *const c_char,321	error: &mut c_int,322) -> *const c_char {323	vm.run_in_state(|| {324		use std::fmt::Write;325		let filename = CStr::from_ptr(filename);326		let snippet = CStr::from_ptr(snippet);327		match vm.evaluate_snippet_to_json(328			&PathBuf::from(filename.to_str().unwrap()),329			&snippet.to_str().unwrap(),330		) {331			Ok(v) => {332				*error = 0;333				CString::new(&*v as &str).unwrap().into_raw()334			}335			Err(e) => {336				*error = 1;337				let mut out = String::new();338				writeln!(out, "{:?}", e.0).unwrap();339				for i in (e.1).0.iter() {340					writeln!(out, "{:?} ---- {}", i.0, i.1).unwrap();341				}342				CString::new(&out as &str).unwrap().into_raw()343			}344		}345	})346}347348#[no_mangle]349pub extern "C" fn jsonnet_evaluate_file_multi() {350	todo!()351}352#[no_mangle]353pub extern "C" fn jsonnet_evaluate_snippet_multi() {354	todo!()355}356#[no_mangle]357pub extern "C" fn jsonnet_evaluate_file_stream() {358	todo!()359}360#[no_mangle]361pub extern "C" fn jsonnet_evaluate_snippet_stream() {362	todo!()363}364365#[no_mangle]366#[allow(clippy::boxed_local)]367pub extern "C" fn jsonnet_destroy(_vm: Box<EvaluationState>) {}