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};222324#[cfg(target_arch = "wasm32")]25#[no_mangle]26pub extern "C" fn _start() {}272829303132#[no_mangle]33pub extern "C" fn jsonnet_version() -> &'static [u8; 8] {34 b"v0.16.0\0"35}3637unsafe fn parse_path(input: &CStr) -> Cow<Path> {38 #[cfg(target_family = "unix")]39 {40 use std::os::unix::ffi::OsStrExt;41 let str = OsStr::from_bytes(input.to_bytes());42 Cow::Borrowed(Path::new(str))43 }44 #[cfg(not(target_family = "unix"))]45 {46 let string = input.to_str().expect("bad utf-8");47 Cow::Borrowed(string.as_ref())48 }49}5051unsafe fn unparse_path(input: &Path) -> Cow<CStr> {52 #[cfg(target_family = "unix")]53 {54 use std::os::unix::ffi::OsStrExt;55 let str = CString::new(input.as_os_str().as_bytes()).expect("input has zero byte in it");56 Cow::Owned(str)57 }58 #[cfg(not(target_family = "unix"))]59 {60 let str = input.as_os_str().to_str().expect("bad utf-8");61 let cstr = CString::new(str).expect("input has NUL inside");62 Cow::Owned(cstr)63 }64}656667#[no_mangle]68#[allow(clippy::box_default)]69pub extern "C" fn jsonnet_make() -> *mut State {70 let state = State::default();71 state.settings_mut().import_resolver = Box::new(FileImportResolver::default());72 state.settings_mut().context_initializer = Box::new(jrsonnet_stdlib::ContextInitializer::new(73 state.clone(),74 PathResolver::new_cwd_fallback(),75 ));76 Box::into_raw(Box::new(state))77}787980#[no_mangle]81#[allow(clippy::boxed_local)]82pub extern "C" fn jsonnet_destroy(vm: Box<State>) {83 drop(vm);84}858687#[no_mangle]88pub extern "C" fn jsonnet_max_stack(vm: &State, v: c_uint) {89 vm.settings_mut().max_stack = v as usize;90}9192939495#[no_mangle]96pub extern "C" fn jsonnet_gc_min_objects(_vm: &State, _v: c_uint) {}979899100101#[no_mangle]102pub extern "C" fn jsonnet_gc_growth_trigger(_vm: &State, _v: c_double) {}103104105#[no_mangle]106pub extern "C" fn jsonnet_string_output(vm: &State, v: c_int) {107 match v {108 1 => vm.set_manifest_format(ManifestFormat::String),109 0 => vm.set_manifest_format(ManifestFormat::Json {110 padding: 4,111 #[cfg(feature = "exp-preserve-order")]112 preserve_order: false,113 }),114 _ => panic!("incorrect output format"),115 }116}117118119120121122123124125126#[no_mangle]127pub unsafe extern "C" fn jsonnet_realloc(_vm: &State, buf: *mut u8, sz: usize) -> *mut u8 {128 if buf.is_null() {129 if sz == 0 {130 return std::ptr::null_mut();131 }132 return std::alloc::alloc(Layout::from_size_align(sz, std::mem::align_of::<u8>()).unwrap());133 }134 135 136 137 138 let old_layout = Layout::from_size_align(16, std::mem::align_of::<u8>()).unwrap();139 if sz == 0 {140 std::alloc::dealloc(buf, old_layout);141 return std::ptr::null_mut();142 }143 std::alloc::realloc(buf, old_layout, sz)144}145146147148149#[no_mangle]150#[allow(clippy::boxed_local)]151pub extern "C" fn jsonnet_json_destroy(_vm: &State, v: Box<Val>) {152 drop(v);153}154155156#[no_mangle]157pub extern "C" fn jsonnet_max_trace(vm: &State, v: c_uint) {158 vm.set_max_trace(v as usize)159}160161162163164165166167168#[no_mangle]169pub unsafe extern "C" fn jsonnet_evaluate_file(170 vm: &State,171 filename: *const c_char,172 error: &mut c_int,173) -> *const c_char {174 let filename = parse_path(CStr::from_ptr(filename));175 match vm176 .import(&filename)177 .and_then(|v| vm.with_tla(v))178 .and_then(|v| vm.manifest(v))179 {180 Ok(v) => {181 *error = 0;182 CString::new(&*v as &str).unwrap().into_raw()183 }184 Err(e) => {185 *error = 1;186 let out = vm.stringify_err(&e);187 CString::new(&out as &str).unwrap().into_raw()188 }189 }190}191192193194195196197198199#[no_mangle]200pub unsafe extern "C" fn jsonnet_evaluate_snippet(201 vm: &State,202 filename: *const c_char,203 snippet: *const c_char,204 error: &mut c_int,205) -> *const c_char {206 let filename = CStr::from_ptr(filename);207 let snippet = CStr::from_ptr(snippet);208 match vm209 .evaluate_snippet(filename.to_str().unwrap(), snippet.to_str().unwrap())210 .and_then(|v| vm.with_tla(v))211 .and_then(|v| vm.manifest(v))212 {213 Ok(v) => {214 *error = 0;215 CString::new(&*v as &str).unwrap().into_raw()216 }217 Err(e) => {218 *error = 1;219 let out = vm.stringify_err(&e);220 CString::new(&out as &str).unwrap().into_raw()221 }222 }223}224225fn multi_to_raw(multi: Vec<(IStr, IStr)>) -> *const c_char {226 let mut out = Vec::new();227 for (i, (k, v)) in multi.iter().enumerate() {228 if i != 0 {229 out.push(0);230 }231 out.extend_from_slice(k.as_bytes());232 out.push(0);233 out.extend_from_slice(v.as_bytes());234 }235 out.push(0);236 out.push(0);237 let v = out.as_ptr();238 std::mem::forget(out);239 v as *const c_char240}241242243#[no_mangle]244pub unsafe extern "C" fn jsonnet_evaluate_file_multi(245 vm: &State,246 filename: *const c_char,247 error: &mut c_int,248) -> *const c_char {249 let filename = parse_path(CStr::from_ptr(filename));250 match vm251 .import(&filename)252 .and_then(|v| vm.with_tla(v))253 .and_then(|v| vm.manifest_multi(v))254 {255 Ok(v) => {256 *error = 0;257 multi_to_raw(v)258 }259 Err(e) => {260 *error = 1;261 let out = vm.stringify_err(&e);262 CString::new(&out as &str).unwrap().into_raw()263 }264 }265}266267268#[no_mangle]269pub unsafe extern "C" fn jsonnet_evaluate_snippet_multi(270 vm: &State,271 filename: *const c_char,272 snippet: *const c_char,273 error: &mut c_int,274) -> *const c_char {275 let filename = CStr::from_ptr(filename);276 let snippet = CStr::from_ptr(snippet);277 match vm278 .evaluate_snippet(filename.to_str().unwrap(), snippet.to_str().unwrap())279 .and_then(|v| vm.with_tla(v))280 .and_then(|v| vm.manifest_multi(v))281 {282 Ok(v) => {283 *error = 0;284 multi_to_raw(v)285 }286 Err(e) => {287 *error = 1;288 let out = vm.stringify_err(&e);289 CString::new(&out as &str).unwrap().into_raw()290 }291 }292}293294fn stream_to_raw(multi: Vec<IStr>) -> *const c_char {295 let mut out = Vec::new();296 for (i, v) in multi.iter().enumerate() {297 if i != 0 {298 out.push(0);299 }300 out.extend_from_slice(v.as_bytes());301 }302 out.push(0);303 out.push(0);304 let v = out.as_ptr();305 std::mem::forget(out);306 v as *const c_char307}308309310#[no_mangle]311pub unsafe extern "C" fn jsonnet_evaluate_file_stream(312 vm: &State,313 filename: *const c_char,314 error: &mut c_int,315) -> *const c_char {316 let filename = parse_path(CStr::from_ptr(filename));317 match vm318 .import(&filename)319 .and_then(|v| vm.with_tla(v))320 .and_then(|v| vm.manifest_stream(v))321 {322 Ok(v) => {323 *error = 0;324 stream_to_raw(v)325 }326 Err(e) => {327 *error = 1;328 let out = vm.stringify_err(&e);329 CString::new(&out as &str)330 .expect("there should be no \\0 in the error string")331 .into_raw()332 }333 }334}335336337#[no_mangle]338pub unsafe extern "C" fn jsonnet_evaluate_snippet_stream(339 vm: &State,340 filename: *const c_char,341 snippet: *const c_char,342 error: &mut c_int,343) -> *const c_char {344 let filename = CStr::from_ptr(filename);345 let snippet = CStr::from_ptr(snippet);346 match vm347 .evaluate_snippet(348 filename.to_str().expect("filename is not utf-8"),349 snippet.to_str().expect("snippet is not utf-8"),350 )351 .and_then(|v| vm.with_tla(v))352 .and_then(|v| vm.manifest_stream(v))353 {354 Ok(v) => {355 *error = 0;356 stream_to_raw(v)357 }358 Err(e) => {359 *error = 1;360 let out = vm.stringify_err(&e);361 CString::new(&out as &str)362 .expect("there should be no \\0 in the error string")363 .into_raw()364 }365 }366}