difftreelog
feat multi and stream manifests
in: master
5 files changed
bindings/jsonnet/src/lib.rsdiffbeforeafterboth1pub mod import;2pub mod interop;3pub mod native;4pub mod val_extract;5pub mod val_make;6pub mod val_modify;7pub mod vars_tlas;89use import::NativeImportResolver;10use jrsonnet_evaluator::{EvaluationState, ManifestFormat, Val};11use std::{12 alloc::Layout,13 ffi::{CStr, CString},14 os::raw::{c_char, c_double, c_int, c_uint},15 path::PathBuf,16 rc::Rc,17};1819/// WASM stub20#[cfg(target_arch = "wasm32")]21#[no_mangle]22pub extern "C" fn _start() {}2324#[no_mangle]25pub extern "C" fn jsonnet_version() -> &'static [u8; 8] {26 b"v0.16.0\0"27}2829#[no_mangle]30pub extern "C" fn jsonnet_make() -> *mut EvaluationState {31 let state = EvaluationState::default();32 state.with_stdlib();33 state.settings_mut().import_resolver = Box::new(NativeImportResolver::default());34 Box::into_raw(Box::new(state))35}3637/// # Safety38#[no_mangle]39#[allow(clippy::boxed_local)]40pub unsafe extern "C" fn jsonnet_destroy(vm: *mut EvaluationState) {41 Box::from_raw(vm);42}4344#[no_mangle]45pub extern "C" fn jsonnet_max_stack(vm: &EvaluationState, v: c_uint) {46 vm.settings_mut().max_stack = v as usize;47}4849// jrsonnet currently have no GC, so these functions is no-op50#[no_mangle]51pub extern "C" fn jsonnet_gc_min_objects(_vm: &EvaluationState, _v: c_uint) {}52#[no_mangle]53pub extern "C" fn jsonnet_gc_growth_trigger(_vm: &EvaluationState, _v: c_double) {}5455#[no_mangle]56pub extern "C" fn jsonnet_string_output(vm: &EvaluationState, v: c_int) {57 match v {58 1 => vm.set_manifest_format(ManifestFormat::String),59 0 => vm.set_manifest_format(ManifestFormat::Json(4)),60 _ => panic!("incorrect output format"),61 }62}6364/// # Safety65///66/// This function is most definitely broken, but it works somehow, see TODO inside67#[no_mangle]68pub unsafe extern "C" fn jsonnet_realloc(69 _vm: &EvaluationState,70 buf: *mut u8,71 sz: usize,72) -> *mut u8 {73 if buf.is_null() {74 assert!(sz != 0);75 return std::alloc::alloc(Layout::from_size_align(sz, std::mem::align_of::<u8>()).unwrap());76 }77 // TODO: Somehow store size of allocation, because its real size is probally not 16 :D78 // OR (Alternative way of fixing this TODO)79 // TODO: Standard allocator uses malloc, and it doesn't uses allocation size,80 // TODO: so it should work in normal cases. Maybe force allocator for this library?81 let old_layout = Layout::from_size_align(16, std::mem::align_of::<u8>()).unwrap();82 if sz == 0 {83 std::alloc::dealloc(buf, old_layout);84 return std::ptr::null_mut();85 }86 std::alloc::realloc(buf, old_layout, sz)87}8889/// # Safety90#[no_mangle]91#[allow(clippy::boxed_local)]92pub unsafe extern "C" fn jsonnet_json_destroy(_vm: &EvaluationState, v: *mut Val) {93 Box::from_raw(v);94}9596#[no_mangle]97pub extern "C" fn jsonnet_max_trace(vm: &EvaluationState, v: c_uint) {98 vm.set_max_trace(v as usize)99}100101/// # Safety102///103/// This function is safe, if received v is a pointer to normal C string104#[no_mangle]105pub unsafe extern "C" fn jsonnet_evaluate_file(106 vm: &EvaluationState,107 filename: *const c_char,108 error: &mut c_int,109) -> *const c_char {110 vm.run_in_state(|| {111 let filename = CStr::from_ptr(filename);112 match vm113 .evaluate_file_raw_nocwd(&PathBuf::from(filename.to_str().unwrap()))114 .and_then(|v| vm.with_tla(v))115 .and_then(|v| vm.manifest(v))116 {117 Ok(v) => {118 *error = 0;119 CString::new(&*v as &str).unwrap().into_raw()120 }121 Err(e) => {122 *error = 1;123 let out = vm.stringify_err(&e);124 CString::new(&out as &str).unwrap().into_raw()125 }126 }127 })128}129130/// # Safety131///132/// This function is safe, if received v is a pointer to normal C string133#[no_mangle]134pub unsafe extern "C" fn jsonnet_evaluate_snippet(135 vm: &EvaluationState,136 filename: *const c_char,137 snippet: *const c_char,138 error: &mut c_int,139) -> *const c_char {140 vm.run_in_state(|| {141 let filename = CStr::from_ptr(filename);142 let snippet = CStr::from_ptr(snippet);143 match vm144 .evaluate_snippet_raw(145 Rc::new(PathBuf::from(filename.to_str().unwrap())),146 snippet.to_str().unwrap().into(),147 )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 })162}163164#[no_mangle]165pub extern "C" fn jsonnet_evaluate_file_multi() {166 todo!()167}168#[no_mangle]169pub extern "C" fn jsonnet_evaluate_snippet_multi() {170 todo!()171}172#[no_mangle]173pub extern "C" fn jsonnet_evaluate_file_stream() {174 todo!()175}176#[no_mangle]177pub extern "C" fn jsonnet_evaluate_snippet_stream() {178 todo!()179}1pub mod import;2pub mod interop;3pub mod native;4pub mod val_extract;5pub mod val_make;6pub mod val_modify;7pub mod vars_tlas;89use import::NativeImportResolver;10use jrsonnet_evaluator::{EvaluationState, ManifestFormat, Val};11use std::{12 alloc::Layout,13 ffi::{CStr, CString},14 os::raw::{c_char, c_double, c_int, c_uint},15 path::PathBuf,16 rc::Rc,17};1819/// WASM stub20#[cfg(target_arch = "wasm32")]21#[no_mangle]22pub extern "C" fn _start() {}2324#[no_mangle]25pub extern "C" fn jsonnet_version() -> &'static [u8; 8] {26 b"v0.16.0\0"27}2829#[no_mangle]30pub extern "C" fn jsonnet_make() -> *mut EvaluationState {31 let state = EvaluationState::default();32 state.with_stdlib();33 state.settings_mut().import_resolver = Box::new(NativeImportResolver::default());34 Box::into_raw(Box::new(state))35}3637/// # Safety38#[no_mangle]39#[allow(clippy::boxed_local)]40pub unsafe extern "C" fn jsonnet_destroy(vm: *mut EvaluationState) {41 Box::from_raw(vm);42}4344#[no_mangle]45pub extern "C" fn jsonnet_max_stack(vm: &EvaluationState, v: c_uint) {46 vm.settings_mut().max_stack = v as usize;47}4849// jrsonnet currently have no GC, so these functions is no-op50#[no_mangle]51pub extern "C" fn jsonnet_gc_min_objects(_vm: &EvaluationState, _v: c_uint) {}52#[no_mangle]53pub extern "C" fn jsonnet_gc_growth_trigger(_vm: &EvaluationState, _v: c_double) {}5455#[no_mangle]56pub extern "C" fn jsonnet_string_output(vm: &EvaluationState, v: c_int) {57 match v {58 1 => vm.set_manifest_format(ManifestFormat::String),59 0 => vm.set_manifest_format(ManifestFormat::Json(4)),60 _ => panic!("incorrect output format"),61 }62}6364/// # Safety65///66/// This function is most definitely broken, but it works somehow, see TODO inside67#[no_mangle]68pub unsafe extern "C" fn jsonnet_realloc(69 _vm: &EvaluationState,70 buf: *mut u8,71 sz: usize,72) -> *mut u8 {73 if buf.is_null() {74 assert!(sz != 0);75 return std::alloc::alloc(Layout::from_size_align(sz, std::mem::align_of::<u8>()).unwrap());76 }77 // TODO: Somehow store size of allocation, because its real size is probally not 16 :D78 // OR (Alternative way of fixing this TODO)79 // TODO: Standard allocator uses malloc, and it doesn't uses allocation size,80 // TODO: so it should work in normal cases. Maybe force allocator for this library?81 let old_layout = Layout::from_size_align(16, std::mem::align_of::<u8>()).unwrap();82 if sz == 0 {83 std::alloc::dealloc(buf, old_layout);84 return std::ptr::null_mut();85 }86 std::alloc::realloc(buf, old_layout, sz)87}8889/// # Safety90#[no_mangle]91#[allow(clippy::boxed_local)]92pub unsafe extern "C" fn jsonnet_json_destroy(_vm: &EvaluationState, v: *mut Val) {93 Box::from_raw(v);94}9596#[no_mangle]97pub extern "C" fn jsonnet_max_trace(vm: &EvaluationState, v: c_uint) {98 vm.set_max_trace(v as usize)99}100101/// # Safety102///103/// This function is safe, if received v is a pointer to normal C string104#[no_mangle]105pub unsafe extern "C" fn jsonnet_evaluate_file(106 vm: &EvaluationState,107 filename: *const c_char,108 error: &mut c_int,109) -> *const c_char {110 vm.run_in_state(|| {111 let filename = CStr::from_ptr(filename);112 match vm113 .evaluate_file_raw_nocwd(&PathBuf::from(filename.to_str().unwrap()))114 .and_then(|v| vm.with_tla(v))115 .and_then(|v| vm.manifest(v))116 {117 Ok(v) => {118 *error = 0;119 CString::new(&*v as &str).unwrap().into_raw()120 }121 Err(e) => {122 *error = 1;123 let out = vm.stringify_err(&e);124 CString::new(&out as &str).unwrap().into_raw()125 }126 }127 })128}129130/// # Safety131///132/// This function is safe, if received v is a pointer to normal C string133#[no_mangle]134pub unsafe extern "C" fn jsonnet_evaluate_snippet(135 vm: &EvaluationState,136 filename: *const c_char,137 snippet: *const c_char,138 error: &mut c_int,139) -> *const c_char {140 vm.run_in_state(|| {141 let filename = CStr::from_ptr(filename);142 let snippet = CStr::from_ptr(snippet);143 match vm144 .evaluate_snippet_raw(145 Rc::new(PathBuf::from(filename.to_str().unwrap())),146 snippet.to_str().unwrap().into(),147 )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 })162}163164fn multi_to_raw(multi: Vec<(Rc<str>, Rc<str>)>) -> *const c_char {165 let mut out = Vec::new();166 for (i, (k, v)) in multi.iter().enumerate() {167 if i != 0 {168 out.push(0);169 }170 out.extend_from_slice(k.as_bytes());171 out.push(0);172 out.extend_from_slice(v.as_bytes());173 }174 out.push(0);175 out.push(0);176 let v = out.as_ptr();177 std::mem::forget(out);178 v as *const c_char179}180181/// # Safety182#[no_mangle]183pub unsafe extern "C" fn jsonnet_evaluate_file_multi(184 vm: &EvaluationState,185 filename: *const c_char,186 error: &mut c_int,187) -> *const c_char {188 vm.run_in_state(|| {189 let filename = CStr::from_ptr(filename);190 match vm191 .evaluate_file_raw_nocwd(&PathBuf::from(filename.to_str().unwrap()))192 .and_then(|v| vm.with_tla(v))193 .and_then(|v| vm.manifest_multi(v))194 {195 Ok(v) => {196 *error = 0;197 multi_to_raw(v)198 }199 Err(e) => {200 *error = 1;201 let out = vm.stringify_err(&e);202 CString::new(&out as &str).unwrap().into_raw()203 }204 }205 })206}207208/// # Safety209#[no_mangle]210pub unsafe extern "C" fn jsonnet_evaluate_snippet_multi(211 vm: &EvaluationState,212 filename: *const c_char,213 snippet: *const c_char,214 error: &mut c_int,215) -> *const c_char {216 vm.run_in_state(|| {217 let filename = CStr::from_ptr(filename);218 let snippet = CStr::from_ptr(snippet);219 match vm220 .evaluate_snippet_raw(221 Rc::new(PathBuf::from(filename.to_str().unwrap())),222 snippet.to_str().unwrap().into(),223 )224 .and_then(|v| vm.with_tla(v))225 .and_then(|v| vm.manifest_multi(v))226 {227 Ok(v) => {228 *error = 0;229 multi_to_raw(v)230 }231 Err(e) => {232 *error = 1;233 let out = vm.stringify_err(&e);234 CString::new(&out as &str).unwrap().into_raw()235 }236 }237 })238}239240fn stream_to_raw(multi: Vec<Rc<str>>) -> *const c_char {241 let mut out = Vec::new();242 for (i, v) in multi.iter().enumerate() {243 if i != 0 {244 out.push(0);245 }246 out.extend_from_slice(v.as_bytes());247 }248 out.push(0);249 out.push(0);250 let v = out.as_ptr();251 std::mem::forget(out);252 v as *const c_char253}254255/// # Safety256#[no_mangle]257pub unsafe extern "C" fn jsonnet_evaluate_file_stream(258 vm: &EvaluationState,259 filename: *const c_char,260 error: &mut c_int,261) -> *const c_char {262 vm.run_in_state(|| {263 let filename = CStr::from_ptr(filename);264 match vm265 .evaluate_file_raw_nocwd(&PathBuf::from(filename.to_str().unwrap()))266 .and_then(|v| vm.with_tla(v))267 .and_then(|v| vm.manifest_stream(v))268 {269 Ok(v) => {270 *error = 0;271 stream_to_raw(v)272 }273 Err(e) => {274 *error = 1;275 let out = vm.stringify_err(&e);276 CString::new(&out as &str).unwrap().into_raw()277 }278 }279 })280}281282/// # Safety283#[no_mangle]284pub unsafe extern "C" fn jsonnet_evaluate_snippet_stream(285 vm: &EvaluationState,286 filename: *const c_char,287 snippet: *const c_char,288 error: &mut c_int,289) -> *const c_char {290 vm.run_in_state(|| {291 let filename = CStr::from_ptr(filename);292 let snippet = CStr::from_ptr(snippet);293 match vm294 .evaluate_snippet_raw(295 Rc::new(PathBuf::from(filename.to_str().unwrap())),296 snippet.to_str().unwrap().into(),297 )298 .and_then(|v| vm.with_tla(v))299 .and_then(|v| vm.manifest_stream(v))300 {301 Ok(v) => {302 *error = 0;303 stream_to_raw(v)304 }305 Err(e) => {306 *error = 1;307 let out = vm.stringify_err(&e);308 CString::new(&out as &str).unwrap().into_raw()309 }310 }311 })312}crates/jrsonnet-evaluator/src/builtin/format.rsdiffbeforeafterboth--- 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(
crates/jrsonnet-evaluator/src/evaluate.rsdiffbeforeafterboth--- 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(
crates/jrsonnet-evaluator/src/lib.rsdiffbeforeafterboth--- 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<Rc<str>> {
self.run_in_state(|| val.manifest(&self.manifest_format()))
}
+ pub fn manifest_multi(&self, val: Val) -> Result<Vec<(Rc<str>, Rc<str>)>> {
+ self.run_in_state(|| val.manifest_multi(&self.manifest_format()))
+ }
+ pub fn manifest_stream(&self, val: Val) -> Result<Vec<Rc<str>>> {
+ 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<Val> {
crates/jrsonnet-evaluator/src/val.rsdiffbeforeafterboth--- a/crates/jrsonnet-evaluator/src/val.rs
+++ b/crates/jrsonnet-evaluator/src/val.rs
@@ -213,7 +213,7 @@
})
}
- pub fn into_string(self) -> Result<Rc<str>> {
+ pub fn to_string(&self) -> Result<Rc<str>> {
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<Vec<(Rc<str>, Rc<str>)>> {
+ 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<Vec<Rc<str>>> {
+ 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<Rc<str>> {
Ok(match ty {