git.delta.rocks / jrsonnet / refs/commits / 54e5a6e38415

difftreelog

feat add std.minArray/std.maxArray

Yaroslav Bolyukin2023-06-14parent: #777cdf5.patch.diff
in: master
Upstream issue: https://github.com/google/jsonnet/pull/1081
Upstream issue: https://github.com/google/jsonnet/pull/1074

2 files changed

modifiedcrates/jrsonnet-stdlib/src/lib.rsdiffbeforeafterboth
112 ("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 // Hash
116 ("md5", builtin_md5::INST),118 ("md5", builtin_md5::INST),
117 ("sha256", builtin_sha256::INST),119 ("sha256", builtin_sha256::INST),
modifiedcrates/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)
+}