difftreelog
feat add std.minArray/std.maxArray
in: master
Upstream issue: https://github.com/google/jsonnet/pull/1081 Upstream issue: https://github.com/google/jsonnet/pull/1074
2 files changed
crates/jrsonnet-stdlib/src/lib.rsdiffbeforeafterboth112 ("sort", builtin_sort::INST),112 ("sort", builtin_sort::INST),113 ("uniq", builtin_uniq::INST),113 ("uniq", builtin_uniq::INST),114 ("set", builtin_set::INST),114 ("set", builtin_set::INST),115 ("minArray", builtin_min_array::INST),116 ("maxArray", builtin_max_array::INST),115 // Hash117 // Hash116 ("md5", builtin_md5::INST),118 ("md5", builtin_md5::INST),117 ("sha256", builtin_sha256::INST),119 ("sha256", builtin_sha256::INST),crates/jrsonnet-stdlib/src/sort.rsdiffbeforeafterboth--- a/crates/jrsonnet-stdlib/src/sort.rs
+++ b/crates/jrsonnet-stdlib/src/sort.rs
@@ -1,3 +1,5 @@
+#![allow(non_snake_case)]
+
use std::cmp::Ordering;
use jrsonnet_evaluator::{
@@ -9,6 +11,7 @@
Thunk, Val,
};
use jrsonnet_gcmodule::Cc;
+use jrsonnet_parser::BinaryOpType;
#[derive(Copy, Clone)]
enum SortKeyType {
@@ -64,15 +67,13 @@
let mut err = None;
// evaluate_compare_op will never return equal on types, which are different from
// jsonnet perspective
- values.sort_unstable_by(|a, b| {
- match evaluate_compare_op(a, b, jrsonnet_parser::BinaryOpType::Lt) {
- Ok(ord) => ord,
- Err(e) if err.is_none() => {
- let _ = err.insert(e);
- Ordering::Equal
- }
- Err(_) => Ordering::Equal,
+ values.sort_unstable_by(|a, b| match evaluate_compare_op(a, b, BinaryOpType::Lt) {
+ Ok(ord) => ord,
+ Err(e) if err.is_none() => {
+ let _ = err.insert(e);
+ Ordering::Equal
}
+ Err(_) => Ordering::Equal,
});
if let Some(err) = err {
return Err(err);
@@ -105,16 +106,16 @@
let mut err = None;
// evaluate_compare_op will never return equal on types, which are different from
// jsonnet perspective
- vk.sort_by(|(_a, ak), (_b, bk)| {
- match evaluate_compare_op(ak, bk, jrsonnet_parser::BinaryOpType::Lt) {
+ vk.sort_by(
+ |(_a, ak), (_b, bk)| match evaluate_compare_op(ak, bk, BinaryOpType::Lt) {
Ok(ord) => ord,
Err(e) if err.is_none() => {
let _ = err.insert(e);
Ordering::Equal
}
Err(_) => Ordering::Equal,
- }
- });
+ },
+ );
if let Some(err) = err {
return Err(err);
}
@@ -138,7 +139,6 @@
}
#[builtin]
-#[allow(non_snake_case)]
pub fn builtin_sort(arr: ArrValue, keyF: Option<FuncVal>) -> Result<ArrValue> {
super::sort::sort(arr, keyF.unwrap_or_else(FuncVal::identity))
}
@@ -206,3 +206,57 @@
Ok(ArrValue::lazy(Cc::new(arr)))
}
}
+
+fn eval_on_empty(on_empty: Option<Thunk<Val>>) -> Result<Val> {
+ if let Some(on_empty) = on_empty {
+ on_empty.evaluate()
+ } else {
+ throw!("expected non-empty array")
+ }
+}
+
+fn eval_keyf(val: Val, key_f: &Option<FuncVal>) -> Result<Val> {
+ if let Some(key_f) = key_f {
+ key_f.evaluate_simple(&(val,), false)
+ } else {
+ Ok(val)
+ }
+}
+
+fn array_top1(arr: ArrValue, key_f: Option<FuncVal>, ordering: Ordering) -> Result<Val> {
+ let mut iter = arr.iter();
+ let mut min = iter.next().expect("not empty")?;
+ let mut min_key = eval_keyf(min.clone(), &key_f)?;
+ for item in iter {
+ let cur = item?;
+ let cur_key = eval_keyf(cur.clone(), &key_f)?;
+ if evaluate_compare_op(&cur_key, &min_key, BinaryOpType::Lt)? == ordering {
+ min = cur;
+ min_key = cur_key;
+ }
+ }
+ Ok(min)
+}
+
+#[builtin]
+pub fn builtin_min_array(
+ arr: ArrValue,
+ keyF: Option<FuncVal>,
+ onEmpty: Option<Thunk<Val>>,
+) -> Result<Val> {
+ if arr.is_empty() {
+ return eval_on_empty(onEmpty);
+ }
+ array_top1(arr, keyF, Ordering::Less)
+}
+#[builtin]
+pub fn builtin_max_array(
+ arr: ArrValue,
+ keyF: Option<FuncVal>,
+ onEmpty: Option<Thunk<Val>>,
+) -> Result<Val> {
+ if arr.is_empty() {
+ return eval_on_empty(onEmpty);
+ }
+ array_top1(arr, keyF, Ordering::Greater)
+}