git.delta.rocks / jrsonnet / refs/commits / 921b9905a568

difftreelog

doc(libjsonnet): copy official documentation to doccomments

Yaroslav Bolyukin2022-08-27parent: #b4d71ec.patch.diff
in: master

7 files changed

modifiedbindings/jsonnet/Cargo.tomldiffbeforeafterboth
--- a/bindings/jsonnet/Cargo.toml
+++ b/bindings/jsonnet/Cargo.toml
@@ -1,5 +1,5 @@
 [package]
-name = "jsonnet"
+name = "libjsonnet"
 description = "Rust implementation of libjsonnet.so"
 version = "0.4.2"
 authors = ["Yaroslav Bolyukin <iam@lach.pw>"]
@@ -14,9 +14,11 @@
 jrsonnet-gcmodule = { version = "0.3.4" }
 
 [lib]
+name = "jsonnet"
 crate-type = ["cdylib"]
 
 [features]
+# Export additional functions for native integration, i.e ability to set custom trace format
 interop = []
 experimental = ["exp-preserve-order", "exp-destruct"]
 exp-preserve-order = ["jrsonnet-evaluator/exp-preserve-order"]
modifiedbindings/jsonnet/src/lib.rsdiffbeforeafterboth
before · bindings/jsonnet/src/lib.rs
1#[cfg(feature = "interop")]2pub mod interop;34pub mod import;5pub mod native;6pub mod val_extract;7pub mod val_make;8pub mod val_modify;9pub mod vars_tlas;1011use std::{12	alloc::Layout,13	env,14	ffi::{CStr, CString},15	os::raw::{c_char, c_double, c_int, c_uint},16};1718use import::NativeImportResolver;19use jrsonnet_evaluator::{IStr, ManifestFormat, State, Val};2021/// WASM stub22#[cfg(target_arch = "wasm32")]23#[no_mangle]24pub extern "C" fn _start() {}2526#[no_mangle]27pub extern "C" fn jsonnet_version() -> &'static [u8; 8] {28	b"v0.16.0\0"29}3031#[no_mangle]32pub extern "C" fn jsonnet_make() -> *mut State {33	let state = State::default();34	state.settings_mut().import_resolver = Box::new(NativeImportResolver::default());35	state.settings_mut().context_initializer =36		Box::new(jrsonnet_stdlib::ContextInitializer::new(state.clone()));37	Box::into_raw(Box::new(state))38}3940/// # Safety41#[no_mangle]42#[allow(clippy::boxed_local)]43pub unsafe extern "C" fn jsonnet_destroy(vm: *mut State) {44	drop(Box::from_raw(vm));45}4647#[no_mangle]48pub extern "C" fn jsonnet_max_stack(vm: &State, v: c_uint) {49	vm.settings_mut().max_stack = v as usize;50}5152// jrsonnet currently have no GC, so these functions is no-op53#[no_mangle]54pub extern "C" fn jsonnet_gc_min_objects(_vm: &State, _v: c_uint) {}55#[no_mangle]56pub extern "C" fn jsonnet_gc_growth_trigger(_vm: &State, _v: c_double) {}5758#[no_mangle]59pub extern "C" fn jsonnet_string_output(vm: &State, v: c_int) {60	match v {61		1 => vm.set_manifest_format(ManifestFormat::String),62		0 => vm.set_manifest_format(ManifestFormat::Json {63			padding: 4,64			#[cfg(feature = "exp-preserve-order")]65			preserve_order: false,66		}),67		_ => panic!("incorrect output format"),68	}69}7071/// # Safety72///73/// This function is most definitely broken, but it works somehow, see TODO inside74#[no_mangle]75pub unsafe extern "C" fn jsonnet_realloc(_vm: &State, buf: *mut u8, sz: usize) -> *mut u8 {76	if buf.is_null() {77		assert!(sz != 0);78		return std::alloc::alloc(Layout::from_size_align(sz, std::mem::align_of::<u8>()).unwrap());79	}80	// TODO: Somehow store size of allocation, because its real size is probally not 16 :D81	// OR (Alternative way of fixing this TODO)82	// TODO: Standard allocator uses malloc, and it doesn't uses allocation size,83	// TODO: so it should work in normal cases. Maybe force allocator for this library?84	let old_layout = Layout::from_size_align(16, std::mem::align_of::<u8>()).unwrap();85	if sz == 0 {86		std::alloc::dealloc(buf, old_layout);87		return std::ptr::null_mut();88	}89	std::alloc::realloc(buf, old_layout, sz)90}9192/// # Safety93#[no_mangle]94#[allow(clippy::boxed_local)]95pub unsafe extern "C" fn jsonnet_json_destroy(_vm: &State, v: *mut Val) {96	drop(Box::from_raw(v));97}9899#[no_mangle]100pub extern "C" fn jsonnet_max_trace(vm: &State, v: c_uint) {101	vm.set_max_trace(v as usize)102}103104/// # Safety105///106/// This function is safe, if received v is a pointer to normal C string107#[no_mangle]108pub unsafe extern "C" fn jsonnet_evaluate_file(109	vm: &State,110	filename: *const c_char,111	error: &mut c_int,112) -> *const c_char {113	let filename = CStr::from_ptr(filename);114	match vm115		.import(116			&env::current_dir().expect("cwd"),117			filename.to_str().unwrap(),118		)119		.and_then(|v| vm.with_tla(v))120		.and_then(|v| vm.manifest(v))121	{122		Ok(v) => {123			*error = 0;124			CString::new(&*v as &str).unwrap().into_raw()125		}126		Err(e) => {127			*error = 1;128			let out = vm.stringify_err(&e);129			CString::new(&out as &str).unwrap().into_raw()130		}131	}132}133134/// # Safety135///136/// This function is safe, if received v is a pointer to normal C string137#[no_mangle]138pub unsafe extern "C" fn jsonnet_evaluate_snippet(139	vm: &State,140	filename: *const c_char,141	snippet: *const c_char,142	error: &mut c_int,143) -> *const c_char {144	let filename = CStr::from_ptr(filename);145	let snippet = CStr::from_ptr(snippet);146	match vm147		.evaluate_snippet(filename.to_str().unwrap().into(), snippet.to_str().unwrap())148		.and_then(|v| vm.with_tla(v))149		.and_then(|v| vm.manifest(v))150	{151		Ok(v) => {152			*error = 0;153			CString::new(&*v as &str).unwrap().into_raw()154		}155		Err(e) => {156			*error = 1;157			let out = vm.stringify_err(&e);158			CString::new(&out as &str).unwrap().into_raw()159		}160	}161}162163fn multi_to_raw(multi: Vec<(IStr, IStr)>) -> *const c_char {164	let mut out = Vec::new();165	for (i, (k, v)) in multi.iter().enumerate() {166		if i != 0 {167			out.push(0);168		}169		out.extend_from_slice(k.as_bytes());170		out.push(0);171		out.extend_from_slice(v.as_bytes());172	}173	out.push(0);174	out.push(0);175	let v = out.as_ptr();176	std::mem::forget(out);177	v as *const c_char178}179180/// # Safety181#[no_mangle]182pub unsafe extern "C" fn jsonnet_evaluate_file_multi(183	vm: &State,184	filename: *const c_char,185	error: &mut c_int,186) -> *const c_char {187	let filename = CStr::from_ptr(filename);188	match vm189		.import(190			&env::current_dir().expect("cwd"),191			filename.to_str().unwrap(),192		)193		.and_then(|v| vm.with_tla(v))194		.and_then(|v| vm.manifest_multi(v))195	{196		Ok(v) => {197			*error = 0;198			multi_to_raw(v)199		}200		Err(e) => {201			*error = 1;202			let out = vm.stringify_err(&e);203			CString::new(&out as &str).unwrap().into_raw()204		}205	}206}207208/// # Safety209#[no_mangle]210pub unsafe extern "C" fn jsonnet_evaluate_snippet_multi(211	vm: &State,212	filename: *const c_char,213	snippet: *const c_char,214	error: &mut c_int,215) -> *const c_char {216	let filename = CStr::from_ptr(filename);217	let snippet = CStr::from_ptr(snippet);218	match vm219		.evaluate_snippet(filename.to_str().unwrap().into(), snippet.to_str().unwrap())220		.and_then(|v| vm.with_tla(v))221		.and_then(|v| vm.manifest_multi(v))222	{223		Ok(v) => {224			*error = 0;225			multi_to_raw(v)226		}227		Err(e) => {228			*error = 1;229			let out = vm.stringify_err(&e);230			CString::new(&out as &str).unwrap().into_raw()231		}232	}233}234235fn stream_to_raw(multi: Vec<IStr>) -> *const c_char {236	let mut out = Vec::new();237	for (i, v) in multi.iter().enumerate() {238		if i != 0 {239			out.push(0);240		}241		out.extend_from_slice(v.as_bytes());242	}243	out.push(0);244	out.push(0);245	let v = out.as_ptr();246	std::mem::forget(out);247	v as *const c_char248}249250/// # Safety251#[no_mangle]252pub unsafe extern "C" fn jsonnet_evaluate_file_stream(253	vm: &State,254	filename: *const c_char,255	error: &mut c_int,256) -> *const c_char {257	let filename = CStr::from_ptr(filename);258	match vm259		.import(260			&env::current_dir().expect("cwd"),261			filename.to_str().unwrap(),262		)263		.and_then(|v| vm.with_tla(v))264		.and_then(|v| vm.manifest_stream(v))265	{266		Ok(v) => {267			*error = 0;268			stream_to_raw(v)269		}270		Err(e) => {271			*error = 1;272			let out = vm.stringify_err(&e);273			CString::new(&out as &str).unwrap().into_raw()274		}275	}276}277278/// # Safety279#[no_mangle]280pub unsafe extern "C" fn jsonnet_evaluate_snippet_stream(281	vm: &State,282	filename: *const c_char,283	snippet: *const c_char,284	error: &mut c_int,285) -> *const c_char {286	let filename = CStr::from_ptr(filename);287	let snippet = CStr::from_ptr(snippet);288	match vm289		.evaluate_snippet(filename.to_str().unwrap().into(), snippet.to_str().unwrap())290		.and_then(|v| vm.with_tla(v))291		.and_then(|v| vm.manifest_stream(v))292	{293		Ok(v) => {294			*error = 0;295			stream_to_raw(v)296		}297		Err(e) => {298			*error = 1;299			let out = vm.stringify_err(&e);300			CString::new(&out as &str).unwrap().into_raw()301		}302	}303}
after · bindings/jsonnet/src/lib.rs
1#[cfg(feature = "interop")]2pub mod interop;34pub mod import;5pub mod native;6pub mod val_extract;7pub mod val_make;8pub mod val_modify;9pub mod vars_tlas;1011use std::{12	alloc::Layout,13	borrow::Cow,14	ffi::{CStr, CString, OsStr},15	os::raw::{c_char, c_double, c_int, c_uint},16	path::Path,17};1819use jrsonnet_evaluator::{20	trace::PathResolver, FileImportResolver, IStr, ManifestFormat, State, Val,21};2223/// WASM stub24#[cfg(target_arch = "wasm32")]25#[no_mangle]26pub extern "C" fn _start() {}2728/// Return the version string of the Jsonnet interpreter.  Conforms to semantic versioning29/// http://semver.org/ If this does not match LIB_JSONNET_VERSION then there is a mismatch between30/// header and compiled library.31#[no_mangle]32pub extern "C" fn jsonnet_version() -> &'static [u8; 8] {33	b"v0.16.0\0"34}3536unsafe fn parse_path(input: &CStr) -> Cow<Path> {37	#[cfg(target_family = "unix")]38	{39		use std::os::unix::ffi::OsStrExt;40		let str = OsStr::from_bytes(input.to_bytes());41		Cow::Borrowed(Path::new(str))42	}43	#[cfg(target_family = "windows")]44	{45		use std::os::windows::ffi::OsStringExt;46		let str = input.to_str().expect("input is not utf8");47		let wide = str.encode_utf16().collect::<Vec<_>>();48		let wide = OsString::from_wide(&wide);49		Cow::Owned(PathBuf::new(wide))50	}51	#[cfg(not(any(target_family = "unix", target_family = "windows")))]52	{53		compile_error!("unsupported os")54	}55}5657unsafe fn unparse_path(input: &Path) -> Cow<CStr> {58	#[cfg(target_family = "unix")]59	{60		use std::os::unix::ffi::OsStrExt;61		let str = CString::new(input.as_os_str().as_bytes()).expect("input has zero byte in it");62		Cow::Owned(str)63	}64	#[cfg(not(any(target_family = "unix", target_family = "windows")))]65	{66		compile_error!("unsupported os")67	}68}6970/// Create a new Jsonnet virtual machine.71#[no_mangle]72pub extern "C" fn jsonnet_make() -> *mut State {73	let state = State::default();74	state.settings_mut().import_resolver = Box::new(FileImportResolver::default());75	state.settings_mut().context_initializer = Box::new(jrsonnet_stdlib::ContextInitializer::new(76		state.clone(),77		PathResolver::new_cwd_fallback(),78	));79	Box::into_raw(Box::new(state))80}8182/// Complement of `jsonnet_vm_make`83#[no_mangle]84#[allow(clippy::boxed_local)]85pub extern "C" fn jsonnet_destroy(vm: Box<State>) {86	drop(vm);87}8889/// Set the maximum stack depth.90#[no_mangle]91pub extern "C" fn jsonnet_max_stack(vm: &State, v: c_uint) {92	vm.settings_mut().max_stack = v as usize;93}9495/// Set the number of objects required before a garbage collection cycle is allowed.96///97/// No-op for now98#[no_mangle]99pub extern "C" fn jsonnet_gc_min_objects(_vm: &State, _v: c_uint) {}100101/// Run the garbage collector after this amount of growth in the number of objects102///103/// No-op for now104#[no_mangle]105pub extern "C" fn jsonnet_gc_growth_trigger(_vm: &State, _v: c_double) {}106107/// Expect a string as output and don't JSON encode it.108#[no_mangle]109pub extern "C" fn jsonnet_string_output(vm: &State, v: c_int) {110	match v {111		1 => vm.set_manifest_format(ManifestFormat::String),112		0 => vm.set_manifest_format(ManifestFormat::Json {113			padding: 4,114			#[cfg(feature = "exp-preserve-order")]115			preserve_order: false,116		}),117		_ => panic!("incorrect output format"),118	}119}120121/// Allocate, resize, or free a buffer.  This will abort if the memory cannot be allocated.  It will122/// only return NULL if sz was zero.123///124/// # Safety125///126/// `buf` should be either previosly allocated by this library, or NULL127///128/// This function is most definitely broken, but it works somehow, see TODO inside129#[no_mangle]130pub unsafe extern "C" fn jsonnet_realloc(_vm: &State, buf: *mut u8, sz: usize) -> *mut u8 {131	if buf.is_null() {132		if sz == 0 {133			return std::ptr::null_mut();134		}135		return std::alloc::alloc(Layout::from_size_align(sz, std::mem::align_of::<u8>()).unwrap());136	}137	// TODO: Somehow store size of allocation, because its real size is probally not 16 :D138	// OR (Alternative way of fixing this TODO)139	// TODO: Standard allocator uses malloc, and it doesn't uses allocation size,140	// TODO: so it should work in normal cases. Maybe force allocator for this library?141	let old_layout = Layout::from_size_align(16, std::mem::align_of::<u8>()).unwrap();142	if sz == 0 {143		std::alloc::dealloc(buf, old_layout);144		return std::ptr::null_mut();145	}146	std::alloc::realloc(buf, old_layout, sz)147}148149/// Clean up a JSON subtree.150///151/// This is useful if you want to abort with an error mid-way through building a complex value.152#[no_mangle]153#[allow(clippy::boxed_local)]154pub extern "C" fn jsonnet_json_destroy(_vm: &State, v: Box<Val>) {155	drop(v);156}157158/// Set the number of lines of stack trace to display (0 for all of them).159#[no_mangle]160pub extern "C" fn jsonnet_max_trace(vm: &State, v: c_uint) {161	vm.set_max_trace(v as usize)162}163164/// Evaluate a file containing Jsonnet code, return a JSON string.165///166/// The returned string should be cleaned up with jsonnet_realloc.167///168/// # Safety169///170/// `filename` should be a \0-terminated string171#[no_mangle]172pub unsafe extern "C" fn jsonnet_evaluate_file(173	vm: &State,174	filename: *const c_char,175	error: &mut c_int,176) -> *const c_char {177	let filename = parse_path(CStr::from_ptr(filename));178	match vm179		.import(&filename)180		.and_then(|v| vm.with_tla(v))181		.and_then(|v| vm.manifest(v))182	{183		Ok(v) => {184			*error = 0;185			CString::new(&*v as &str).unwrap().into_raw()186		}187		Err(e) => {188			*error = 1;189			let out = vm.stringify_err(&e);190			CString::new(&out as &str).unwrap().into_raw()191		}192	}193}194195/// Evaluate a string containing Jsonnet code, return a JSON string.196///197/// The returned string should be cleaned up with jsonnet_realloc.198///199/// # Safety200///201/// `filename`, `snippet` should be a \0-terminated strings202#[no_mangle]203pub unsafe extern "C" fn jsonnet_evaluate_snippet(204	vm: &State,205	filename: *const c_char,206	snippet: *const c_char,207	error: &mut c_int,208) -> *const c_char {209	let filename = CStr::from_ptr(filename);210	let snippet = CStr::from_ptr(snippet);211	match vm212		.evaluate_snippet(filename.to_str().unwrap(), snippet.to_str().unwrap())213		.and_then(|v| vm.with_tla(v))214		.and_then(|v| vm.manifest(v))215	{216		Ok(v) => {217			*error = 0;218			CString::new(&*v as &str).unwrap().into_raw()219		}220		Err(e) => {221			*error = 1;222			let out = vm.stringify_err(&e);223			CString::new(&out as &str).unwrap().into_raw()224		}225	}226}227228fn multi_to_raw(multi: Vec<(IStr, IStr)>) -> *const c_char {229	let mut out = Vec::new();230	for (i, (k, v)) in multi.iter().enumerate() {231		if i != 0 {232			out.push(0);233		}234		out.extend_from_slice(k.as_bytes());235		out.push(0);236		out.extend_from_slice(v.as_bytes());237	}238	out.push(0);239	out.push(0);240	let v = out.as_ptr();241	std::mem::forget(out);242	v as *const c_char243}244245/// # Safety246#[no_mangle]247pub unsafe extern "C" fn jsonnet_evaluate_file_multi(248	vm: &State,249	filename: *const c_char,250	error: &mut c_int,251) -> *const c_char {252	let filename = parse_path(CStr::from_ptr(filename));253	match vm254		.import(&filename)255		.and_then(|v| vm.with_tla(v))256		.and_then(|v| vm.manifest_multi(v))257	{258		Ok(v) => {259			*error = 0;260			multi_to_raw(v)261		}262		Err(e) => {263			*error = 1;264			let out = vm.stringify_err(&e);265			CString::new(&out as &str).unwrap().into_raw()266		}267	}268}269270/// # Safety271#[no_mangle]272pub unsafe extern "C" fn jsonnet_evaluate_snippet_multi(273	vm: &State,274	filename: *const c_char,275	snippet: *const c_char,276	error: &mut c_int,277) -> *const c_char {278	let filename = CStr::from_ptr(filename);279	let snippet = CStr::from_ptr(snippet);280	match vm281		.evaluate_snippet(filename.to_str().unwrap(), snippet.to_str().unwrap())282		.and_then(|v| vm.with_tla(v))283		.and_then(|v| vm.manifest_multi(v))284	{285		Ok(v) => {286			*error = 0;287			multi_to_raw(v)288		}289		Err(e) => {290			*error = 1;291			let out = vm.stringify_err(&e);292			CString::new(&out as &str).unwrap().into_raw()293		}294	}295}296297fn stream_to_raw(multi: Vec<IStr>) -> *const c_char {298	let mut out = Vec::new();299	for (i, v) in multi.iter().enumerate() {300		if i != 0 {301			out.push(0);302		}303		out.extend_from_slice(v.as_bytes());304	}305	out.push(0);306	out.push(0);307	let v = out.as_ptr();308	std::mem::forget(out);309	v as *const c_char310}311312/// # Safety313#[no_mangle]314pub unsafe extern "C" fn jsonnet_evaluate_file_stream(315	vm: &State,316	filename: *const c_char,317	error: &mut c_int,318) -> *const c_char {319	let filename = parse_path(CStr::from_ptr(filename));320	match vm321		.import(&filename)322		.and_then(|v| vm.with_tla(v))323		.and_then(|v| vm.manifest_stream(v))324	{325		Ok(v) => {326			*error = 0;327			stream_to_raw(v)328		}329		Err(e) => {330			*error = 1;331			let out = vm.stringify_err(&e);332			CString::new(&out as &str)333				.expect("there should be no \\0 in the error string")334				.into_raw()335		}336	}337}338339/// # Safety340#[no_mangle]341pub unsafe extern "C" fn jsonnet_evaluate_snippet_stream(342	vm: &State,343	filename: *const c_char,344	snippet: *const c_char,345	error: &mut c_int,346) -> *const c_char {347	let filename = CStr::from_ptr(filename);348	let snippet = CStr::from_ptr(snippet);349	match vm350		.evaluate_snippet(351			filename.to_str().expect("filename is not utf-8"),352			snippet.to_str().expect("snippet is not utf-8"),353		)354		.and_then(|v| vm.with_tla(v))355		.and_then(|v| vm.manifest_stream(v))356	{357		Ok(v) => {358			*error = 0;359			stream_to_raw(v)360		}361		Err(e) => {362			*error = 1;363			let out = vm.stringify_err(&e);364			CString::new(&out as &str)365				.expect("there should be no \\0 in the error string")366				.into_raw()367		}368	}369}
modifiedbindings/jsonnet/src/native.rsdiffbeforeafterboth
--- a/bindings/jsonnet/src/native.rs
+++ b/bindings/jsonnet/src/native.rs
@@ -12,6 +12,15 @@
 };
 use jrsonnet_gcmodule::Cc;
 
+/// The returned JsonnetJsonValue* should be allocated with jsonnet_realloc.  It will be cleaned up
+/// along with the objects rooted at argv by libjsonnet when no-longer needed.  Return a string upon
+/// failure, which will appear in Jsonnet as an error.  The argv pointer is an array whose size
+/// matches the array of parameters supplied when the native callback was originally registered.
+///
+/// - `ctx` User pointer, given in jsonnet_native_callback.
+/// - `argv` Array of arguments from Jsonnet code.
+/// - `param` success Set this byref param to 1 to indicate success and 0 for failure.
+/// Returns the content of the imported file, or an error message.
 type JsonnetNativeCallback = unsafe extern "C" fn(
 	ctx: *const c_void,
 	argv: *const *const Val,
@@ -44,13 +53,20 @@
 		if success == 1 {
 			Ok(v)
 		} else {
-			let e = IStr::from_untyped(v, s).expect("error msg");
+			let e = IStr::from_untyped(v, s).expect("error msg should be a string");
 			Err(Error::RuntimeError(e).into())
 		}
 	}
 }
 
+/// Callback to provide native extensions to Jsonnet.
+///
 /// # Safety
+///
+/// `vm` should be a vm allocated by `jsonnet_make`
+/// `cb` should be a correct function pointer
+/// `raw_params` should point to a NULL-terminated string array
+/// `name`, `raw_params` elements should be a \0-terminated strings
 #[no_mangle]
 pub unsafe extern "C" fn jsonnet_native_callback(
 	vm: &State,
@@ -59,13 +75,18 @@
 	ctx: *const c_void,
 	mut raw_params: *const *const c_char,
 ) {
-	let name = CStr::from_ptr(name).to_str().expect("utf8 name").into();
+	let name = CStr::from_ptr(name)
+		.to_str()
+		.expect("name is not utf-8")
+		.into();
 	let mut params = Vec::new();
 	loop {
 		if (*raw_params).is_null() {
 			break;
 		}
-		let param = CStr::from_ptr(*raw_params).to_str().expect("not utf8");
+		let param = CStr::from_ptr(*raw_params)
+			.to_str()
+			.expect("param name is not utf-8");
 		params.push(BuiltinParam {
 			name: param.into(),
 			has_default: false,
modifiedbindings/jsonnet/src/val_extract.rsdiffbeforeafterboth
--- a/bindings/jsonnet/src/val_extract.rs
+++ b/bindings/jsonnet/src/val_extract.rs
@@ -7,6 +7,7 @@
 
 use jrsonnet_evaluator::{State, Val};
 
+/// If the value is a string, return it as UTF8 otherwise return NULL.
 #[no_mangle]
 pub extern "C" fn jsonnet_json_extract_string(_vm: &State, v: &Val) -> *mut c_char {
 	match v {
@@ -14,6 +15,8 @@
 		_ => std::ptr::null_mut(),
 	}
 }
+
+/// If the value is a number, return 1 and store the number in out, otherwise return 0.
 #[no_mangle]
 pub extern "C" fn jsonnet_json_extract_number(_vm: &State, v: &Val, out: &mut c_double) -> c_int {
 	match v {
@@ -24,6 +27,8 @@
 		_ => 0,
 	}
 }
+
+/// Return 0 if the value is false, 1 if it is true, and 2 if it is not a bool.
 #[no_mangle]
 pub extern "C" fn jsonnet_json_extract_bool(_vm: &State, v: &Val) -> c_int {
 	match v {
@@ -32,6 +37,8 @@
 		_ => 2,
 	}
 }
+
+/// Return 1 if the value is null, else 0.
 #[no_mangle]
 pub extern "C" fn jsonnet_json_extract_null(_vm: &State, v: &Val) -> c_int {
 	match v {
modifiedbindings/jsonnet/src/val_make.rsdiffbeforeafterboth
--- a/bindings/jsonnet/src/val_make.rs
+++ b/bindings/jsonnet/src/val_make.rs
@@ -8,37 +8,46 @@
 use jrsonnet_evaluator::{val::ArrValue, ObjValue, State, Val};
 use jrsonnet_gcmodule::Cc;
 
+/// Convert the given UTF8 string to a JsonnetJsonValue.
+///
 /// # Safety
 ///
-/// This function is safe, if received v is a pointer to normal C string
+/// `v` should be a \0-terminated string
 #[no_mangle]
-pub unsafe extern "C" fn jsonnet_json_make_string(_vm: &State, v: *const c_char) -> *mut Val {
-	let cstr = CStr::from_ptr(v);
-	let str = cstr.to_str().unwrap();
-	Box::into_raw(Box::new(Val::Str(str.into())))
+pub unsafe extern "C" fn jsonnet_json_make_string(_vm: &State, val: *const c_char) -> *mut Val {
+	let val = CStr::from_ptr(val);
+	let val = val.to_str().expect("string is not utf-8");
+	Box::into_raw(Box::new(Val::Str(val.into())))
 }
 
+/// Convert the given double to a JsonnetJsonValue.
 #[no_mangle]
 pub extern "C" fn jsonnet_json_make_number(_vm: &State, v: c_double) -> *mut Val {
 	Box::into_raw(Box::new(Val::Num(v)))
 }
 
+/// Convert the given bool (1 or 0) to a JsonnetJsonValue.
 #[no_mangle]
 pub extern "C" fn jsonnet_json_make_bool(_vm: &State, v: c_int) -> *mut Val {
-	assert!(v == 0 || v == 1);
+	assert!(v == 0 || v == 1, "bad boolean value");
 	Box::into_raw(Box::new(Val::Bool(v == 1)))
 }
 
+/// Make a JsonnetJsonValue representing null.
 #[no_mangle]
 pub extern "C" fn jsonnet_json_make_null(_vm: &State) -> *mut Val {
 	Box::into_raw(Box::new(Val::Null))
 }
 
+/// Make a JsonnetJsonValue representing an array.
+///
+/// Assign elements with jsonnet_json_array_append.
 #[no_mangle]
 pub extern "C" fn jsonnet_json_make_array(_vm: &State) -> *mut Val {
 	Box::into_raw(Box::new(Val::Arr(ArrValue::Eager(Cc::new(Vec::new())))))
 }
 
+/// Make a JsonnetJsonValue representing an object.
 #[no_mangle]
 pub extern "C" fn jsonnet_json_make_object(_vm: &State) -> *mut Val {
 	Box::into_raw(Box::new(Val::Obj(ObjValue::new_empty())))
modifiedbindings/jsonnet/src/val_modify.rsdiffbeforeafterboth
--- a/bindings/jsonnet/src/val_modify.rs
+++ b/bindings/jsonnet/src/val_modify.rs
@@ -7,9 +7,12 @@
 use jrsonnet_evaluator::{val::ArrValue, State, Thunk, Val};
 use jrsonnet_gcmodule::Cc;
 
+/// Add value to the end of the array arr
+///
 /// # Safety
 ///
-/// Received arr value should be correct pointer to array allocated by make_array
+/// `arr` should be correct pointer to array value allocated by make_array, or returned by other library call
+/// `val` should be correct pointer to value allocated using this library
 #[no_mangle]
 pub unsafe extern "C" fn jsonnet_json_array_append(_vm: &State, arr: &mut Val, val: &Val) {
 	match arr {
@@ -26,9 +29,14 @@
 	}
 }
 
+/// Add the field to the object, bound to value.
+///
+/// This shadows any previous binding of the field.
+///
 /// # Safety
 ///
-/// This function is safe if passed name is ok
+/// `obj` should be pointer to object value allocated by make_object, or returned by other library call
+/// `name` should be \0-terminated string
 #[no_mangle]
 pub unsafe extern "C" fn jsonnet_json_object_append(
 	_vm: &State,
modifiedbindings/jsonnet/src/vars_tlas.rsdiffbeforeafterboth
--- a/bindings/jsonnet/src/vars_tlas.rs
+++ b/bindings/jsonnet/src/vars_tlas.rs
@@ -4,52 +4,84 @@
 
 use jrsonnet_evaluator::State;
 
+/// Bind a Jsonnet external var to the given string.
+///
+/// Argument values are copied so memory should be managed by caller.
+///
 /// # Safety
+///
+/// Caller should pass correct pointers as `name` and `code`, they need to be \0-terminated strings
 #[no_mangle]
 pub unsafe extern "C" fn jsonnet_ext_var(vm: &State, name: *const c_char, value: *const c_char) {
 	let name = CStr::from_ptr(name);
 	let value = CStr::from_ptr(value);
 
-	let any_resolver = vm.context_initializer();
-	any_resolver
+	let any_initializer = vm.context_initializer();
+	any_initializer
 		.as_any()
 		.downcast_ref::<jrsonnet_stdlib::ContextInitializer>()
 		.expect("only stdlib context initializer supported")
 		.add_ext_str(
-			name.to_str().unwrap().into(),
-			value.to_str().unwrap().into(),
+			name.to_str().expect("name is not utf-8").into(),
+			value.to_str().expect("value is not utf-8").into(),
 		)
 }
 
+/// Bind a Jsonnet external var to the given code.
+///
+/// Argument values are copied so memory should be managed by caller.
+///
 /// # Safety
+///
+/// Caller should pass correct pointers as `name` and `code`, they need to be \0-terminated strings
 #[no_mangle]
-pub unsafe extern "C" fn jsonnet_ext_code(vm: &State, name: *const c_char, value: *const c_char) {
+pub unsafe extern "C" fn jsonnet_ext_code(vm: &State, name: *const c_char, code: *const c_char) {
 	let name = CStr::from_ptr(name);
-	let value = CStr::from_ptr(value);
+	let code = CStr::from_ptr(code);
 
-	let any_resolver = vm.context_initializer();
-	any_resolver
+	let any_initializer = vm.context_initializer();
+	any_initializer
 		.as_any()
 		.downcast_ref::<jrsonnet_stdlib::ContextInitializer>()
 		.expect("only stdlib context initializer supported")
-		.add_ext_code(name.to_str().unwrap(), value.to_str().unwrap())
-		.unwrap()
+		.add_ext_code(
+			name.to_str().expect("name is not utf-8"),
+			code.to_str().expect("code is not utf-8"),
+		)
+		.expect("can't parse ext code")
 }
+
+/// Bind a string top-level argument for a top-level parameter.
+///
+/// Argument values are copied so memory should be managed by caller.
+///
 /// # Safety
+///
+/// Caller should pass correct pointers as `name` and `value`, they need to be \0-terminated strings
 #[no_mangle]
 pub unsafe extern "C" fn jsonnet_tla_var(vm: &State, name: *const c_char, value: *const c_char) {
 	let name = CStr::from_ptr(name);
 	let value = CStr::from_ptr(value);
 	vm.add_tla_str(
-		name.to_str().unwrap().into(),
-		value.to_str().unwrap().into(),
+		name.to_str().expect("name is not utf-8").into(),
+		value.to_str().expect("value is not utf-8").into(),
 	)
 }
+
+/// Bind a code top-level argument for a top-level parameter.
+///
+/// Argument values are copied so memory should be managed by caller.
+///
 /// # Safety
+///
+/// Caller should pass correct pointers as `name` and `code`, they need to be \0-terminated strings
 #[no_mangle]
-pub unsafe extern "C" fn jsonnet_tla_code(vm: &State, name: *const c_char, value: *const c_char) {
+pub unsafe extern "C" fn jsonnet_tla_code(vm: &State, name: *const c_char, code: *const c_char) {
 	let name = CStr::from_ptr(name);
-	let value = CStr::from_ptr(value);
-	vm.add_tla_code(name.to_str().unwrap().into(), value.to_str().unwrap())
-		.unwrap()
+	let code = CStr::from_ptr(code);
+	vm.add_tla_code(
+		name.to_str().expect("name is not utf-8").into(),
+		code.to_str().expect("code is not utf-8"),
+	)
+	.expect("can't parse tla code")
 }