--- a/bindings/jsonnet/src/lib.rs +++ b/bindings/jsonnet/src/lib.rs @@ -161,19 +161,152 @@ }) } +fn multi_to_raw(multi: Vec<(Rc, Rc)>) -> *const c_char { + let mut out = Vec::new(); + for (i, (k, v)) in multi.iter().enumerate() { + if i != 0 { + out.push(0); + } + out.extend_from_slice(k.as_bytes()); + out.push(0); + out.extend_from_slice(v.as_bytes()); + } + out.push(0); + out.push(0); + let v = out.as_ptr(); + std::mem::forget(out); + v as *const c_char +} + +/// # Safety #[no_mangle] -pub extern "C" fn jsonnet_evaluate_file_multi() { - todo!() +pub unsafe extern "C" fn jsonnet_evaluate_file_multi( + vm: &EvaluationState, + filename: *const c_char, + error: &mut c_int, +) -> *const c_char { + vm.run_in_state(|| { + let filename = CStr::from_ptr(filename); + match vm + .evaluate_file_raw_nocwd(&PathBuf::from(filename.to_str().unwrap())) + .and_then(|v| vm.with_tla(v)) + .and_then(|v| vm.manifest_multi(v)) + { + Ok(v) => { + *error = 0; + multi_to_raw(v) + } + Err(e) => { + *error = 1; + let out = vm.stringify_err(&e); + CString::new(&out as &str).unwrap().into_raw() + } + } + }) } + +/// # Safety #[no_mangle] -pub extern "C" fn jsonnet_evaluate_snippet_multi() { - todo!() +pub unsafe extern "C" fn jsonnet_evaluate_snippet_multi( + vm: &EvaluationState, + filename: *const c_char, + snippet: *const c_char, + error: &mut c_int, +) -> *const c_char { + vm.run_in_state(|| { + let filename = CStr::from_ptr(filename); + let snippet = CStr::from_ptr(snippet); + match vm + .evaluate_snippet_raw( + Rc::new(PathBuf::from(filename.to_str().unwrap())), + snippet.to_str().unwrap().into(), + ) + .and_then(|v| vm.with_tla(v)) + .and_then(|v| vm.manifest_multi(v)) + { + Ok(v) => { + *error = 0; + multi_to_raw(v) + } + Err(e) => { + *error = 1; + let out = vm.stringify_err(&e); + CString::new(&out as &str).unwrap().into_raw() + } + } + }) } + +fn stream_to_raw(multi: Vec>) -> *const c_char { + let mut out = Vec::new(); + for (i, v) in multi.iter().enumerate() { + if i != 0 { + out.push(0); + } + out.extend_from_slice(v.as_bytes()); + } + out.push(0); + out.push(0); + let v = out.as_ptr(); + std::mem::forget(out); + v as *const c_char +} + +/// # Safety #[no_mangle] -pub extern "C" fn jsonnet_evaluate_file_stream() { - todo!() +pub unsafe extern "C" fn jsonnet_evaluate_file_stream( + vm: &EvaluationState, + filename: *const c_char, + error: &mut c_int, +) -> *const c_char { + vm.run_in_state(|| { + let filename = CStr::from_ptr(filename); + match vm + .evaluate_file_raw_nocwd(&PathBuf::from(filename.to_str().unwrap())) + .and_then(|v| vm.with_tla(v)) + .and_then(|v| vm.manifest_stream(v)) + { + Ok(v) => { + *error = 0; + stream_to_raw(v) + } + Err(e) => { + *error = 1; + let out = vm.stringify_err(&e); + CString::new(&out as &str).unwrap().into_raw() + } + } + }) } + +/// # Safety #[no_mangle] -pub extern "C" fn jsonnet_evaluate_snippet_stream() { - todo!() +pub unsafe extern "C" fn jsonnet_evaluate_snippet_stream( + vm: &EvaluationState, + filename: *const c_char, + snippet: *const c_char, + error: &mut c_int, +) -> *const c_char { + vm.run_in_state(|| { + let filename = CStr::from_ptr(filename); + let snippet = CStr::from_ptr(snippet); + match vm + .evaluate_snippet_raw( + Rc::new(PathBuf::from(filename.to_str().unwrap())), + snippet.to_str().unwrap().into(), + ) + .and_then(|v| vm.with_tla(v)) + .and_then(|v| vm.manifest_stream(v)) + { + Ok(v) => { + *error = 0; + stream_to_raw(v) + } + Err(e) => { + *error = 1; + let out = vm.stringify_err(&e); + CString::new(&out as &str).unwrap().into_raw() + } + } + }) } --- a/crates/jrsonnet-evaluator/src/builtin/format.rs +++ b/crates/jrsonnet-evaluator/src/builtin/format.rs @@ -470,7 +470,7 @@ let mut tmp_out = String::new(); match code.convtype { - ConvTypeV::String => tmp_out.push_str(&value.clone().into_string()?), + ConvTypeV::String => tmp_out.push_str(&value.clone().to_string()?), ConvTypeV::Decimal => { let value = value.clone().try_cast_num("%d/%u/%i requires number")?; render_decimal( --- a/crates/jrsonnet-evaluator/src/evaluate.rs +++ b/crates/jrsonnet-evaluator/src/evaluate.rs @@ -95,8 +95,8 @@ (Val::Num(n), Val::Str(o)) => Val::Str(format!("{}{}", n, o).into()), (Val::Str(o), Val::Num(n)) => Val::Str(format!("{}{}", o, n).into()), - (Val::Str(s), o) => Val::Str(format!("{}{}", s, o.clone().into_string()?).into()), - (o, Val::Str(s)) => Val::Str(format!("{}{}", o.clone().into_string()?, s).into()), + (Val::Str(s), o) => Val::Str(format!("{}{}", s, o.clone().to_string()?).into()), + (o, Val::Str(s)) => Val::Str(format!("{}{}", o.clone().to_string()?, s).into()), (Val::Obj(v1), Val::Obj(v2)) => Val::Obj(v2.with_super(v1.clone())), (Val::Arr(a), Val::Arr(b)) => Val::Arr(Rc::new([&a[..], &b[..]].concat())), @@ -975,9 +975,9 @@ if assertion_result { evaluate(context, returned)? } else if let Some(msg) = msg { - throw!(AssertionFailed(evaluate(context, msg)?)); + throw!(AssertionFailed(evaluate(context, msg)?.to_string()?)); } else { - throw!(AssertionFailed(Val::Null)); + throw!(AssertionFailed(Val::Null.to_string()?)); } } ErrorStmt(e) => push( --- a/crates/jrsonnet-evaluator/src/lib.rs +++ b/crates/jrsonnet-evaluator/src/lib.rs @@ -321,6 +321,12 @@ pub fn manifest(&self, val: Val) -> Result> { self.run_in_state(|| val.manifest(&self.manifest_format())) } + pub fn manifest_multi(&self, val: Val) -> Result, Rc)>> { + self.run_in_state(|| val.manifest_multi(&self.manifest_format())) + } + pub fn manifest_stream(&self, val: Val) -> Result>> { + self.run_in_state(|| val.manifest_stream(&self.manifest_format())) + } /// If passed value is function - call with set TLA pub fn with_tla(&self, val: Val) -> Result { --- a/crates/jrsonnet-evaluator/src/val.rs +++ b/crates/jrsonnet-evaluator/src/val.rs @@ -213,7 +213,7 @@ }) } - pub fn into_string(self) -> Result> { + pub fn to_string(&self) -> Result> { Ok(match self.unwrap_if_lazy()? { Val::Bool(true) => "true".into(), Val::Bool(false) => "false".into(), @@ -230,6 +230,36 @@ }) } + /// Expects value to be object, outputs (key, manifested value) pairs + pub fn manifest_multi(&self, ty: &ManifestFormat) -> Result, Rc)>> { + let obj = match self { + Val::Obj(obj) => obj, + _ => throw!(MultiManifestOutputIsNotAObject), + }; + let keys = obj.visible_fields(); + let mut out = Vec::with_capacity(keys.len()); + for key in keys { + let value = obj + .get(key.clone())? + .expect("item in object") + .manifest(ty)?; + out.push((key, value)); + } + Ok(out) + } + + /// Expects value to be array, outputs manifested values + pub fn manifest_stream(&self, ty: &ManifestFormat) -> Result>> { + let arr = match self { + Val::Arr(a) => a, + _ => throw!(StreamManifestOutputIsNotAArray), + }; + let mut out = Vec::with_capacity(arr.len()); + for i in arr.iter() { + out.push(i.manifest(ty)?); + } + Ok(out) + } pub fn manifest(&self, ty: &ManifestFormat) -> Result> { Ok(match ty {